Image Transformations
Image transformations let you serve optimized versions of your images automatically. Instead of manually creating multiple sizes, Pixflare generates them on-demand and caches them at the edge.
Why transformations matter
Serving the right image size saves bandwidth, speeds up your site, and improves user experience. A mobile device doesn't need a 4K desktop image. Transformations handle this automatically:
- Bandwidth savings: A 512px image is 80-90% smaller than a 2048px original
- Faster page loads: Smaller images mean quicker downloads
- Modern formats: Automatic conversion to AVIF or WebP based on browser support
- No manual work: Request any size via URL, generated on first use
- Edge caching: Transformed images cached globally for instant delivery
Pixflare includes 9 built-in presets: w128, w256, w512, w1024, w1536, w2048 (width-constrained), thumb (128x128 square), og-image (1200x630 social cards), and original (unmodified). All variants use quality 85, auto-negotiate format (AVIF/WebP), and strip EXIF metadata by default.
Setup
Configure transformations with the following environment variables:
# Required - public R2 custom domain (needed for Cloudflare Image Resizing)
R2_CUSTOM_DOMAIN='r2.yourdomain.com'
# Optional - control available presets
ALLOWED_VARIANTS='["w128","w256","w512","w1024","w1536","w2048","thumb","og-image"]'
DEFAULT_VARIANT='w1024'
# Optional - enable background variant storage (requires queues)
ENABLE_QUEUES='true'R2 Custom Domain
Transformations require a public custom domain on your R2 bucket:
- Go to R2 bucket settings in Cloudflare dashboard
- Add custom domain (e.g.,
r2.yourdomain.com) - Configure DNS as instructed
- Set
R2_CUSTOM_DOMAINin your config
Without this, Pixflare falls back to serving original images only.
Adding Custom Presets
To add new variants, edit packages/config/src/image-variants.ts and add your preset to VARIANT_PRESETS and VARIANT_CONFIG, then rebuild and deploy.
How it Works
When a user requests an image variant, Pixflare checks if it's already been generated. If so, it's served instantly from R2. If not, Cloudflare Image Resizing transforms it on-demand, serves it immediately, then stores it for next time.
sequenceDiagram
participant Client
participant Gateway as Gateway Worker
participant API as API Worker
participant D1 as D1 Database
participant R2 as R2 Storage
participant CF as Cloudflare Image Resizing
participant Queue as Queue (Background)
Client->>Gateway: GET /alice/vacation/beach.jpg/w512
Gateway->>API: Route to CDN handler
API->>D1: Check image exists, privacy, deleted
alt Image not found or deleted
D1-->>API: Not found
API-->>Client: 404 or 410
end
API->>R2: Try fetch pre-generated variant
alt Variant exists in R2
R2-->>API: Return variant
API-->>Client: 200 with transformed image<br/>(Cache-Control: immutable, 1 year)
else Variant not generated yet
R2-->>API: Not found
API->>R2: Fetch original image
R2-->>API: Original image data
API->>CF: Transform on-demand<br/>(via cf.image fetch option)
CF-->>API: Transformed image
API->>Queue: Enqueue background generation
API-->>Client: 200 with transformed image
Queue-->>R2: Store variant for next time
endCaching strategy
Images use multi-layer caching for performance:
- Edge cache: Cloudflare caches all images globally with 1-year TTL (immutable URLs)
- R2 storage: Pre-generated variants stored permanently until image deletion
- Rate limiting: KV-based limits prevent abuse of on-demand generation (100 req/60s per IP)
Cache invalidation happens automatically when you delete an image via the Cloudflare API (requires CLOUDFLARE_ZONE_ID and CLOUDFLARE_API_TOKEN).
Pricing
Transformations work on the free Workers tier via on-demand generation. Images are served instantly but variants aren't stored.
On the paid Workers plan ($5/month), enable queues with ENABLE_QUEUES='true' to persist variants in R2 for faster subsequent requests. See the Queues documentation for setup.
Customization
Custom presets can configure width, height, fit mode (scale-down, cover, contain), format (AVIF, WebP, JPEG), quality (1-100), gravity for smart cropping, and various effects. Edit packages/config/src/image-variants.ts to add your own presets with specific dimensions and options. Cloudflare Image Resizing supports up to 4096x4096px.
Security & Performance
Built-in protections
- Rate limiting: On-demand generation limited to 100 requests per 60 seconds per IP (pre-generated variants unlimited)
- Privacy: Private images require authentication (API key, JWT, or owner verification)
- Immutable caching: 1-year TTL on images with automatic edge caching across 300+ Cloudflare locations
- Format negotiation: Automatic AVIF/WebP serving based on browser support (60% smaller than JPEG)
- Lazy generation: Variants only created when requested, not on upload
- CORS enabled: Images embeddable anywhere with optimized preflight caching
Monitoring
Analytics Engine tracks variant popularity, bandwidth savings, cache hit rates, and geographic distribution. Use this data to optimise your preset configuration.