Skip to content
Last updated

The Image CDN provides on-the-fly image optimization via CloudFront + Lambda@Edge. All images served through the CDN are automatically compressed and converted to modern formats (WebP/AVIF) based on browser support.

Default Behavior

Images are returned at original dimensions (capped at 2048px max) with format conversion. Smaller images are served at original size. Use presets for specific sizes:

  • Listings: ?preset=medium (600×600)
  • Thumbnails: ?preset=thumb (150×150)
  • Full size (up to 2048): no params needed

CDN URLs

EnvironmentCDN Base URL
Developmenthttps://d3bznwycx2s7pk.cloudfront.net
Productionhttps://d949acbs6mj2e.cloudfront.net

Quick Start


# CDN URL - original dimensions (max 2048px), WebP if supported
https://d3bznwycx2s7pk.cloudfront.net/images/photo.png

# Listings/galleries (600×600)
https://d3bznwycx2s7pk.cloudfront.net/images/photo.png?preset=medium

# Thumbnail (150×150)
https://d3bznwycx2s7pk.cloudfront.net/images/photo.png?preset=thumb

# High quality large (1200×1200)
https://d3bznwycx2s7pk.cloudfront.net/images/photo.png?preset=large&q=95

Presets

Use presets for consistent image sizes across the application:

PresetDimensionsUse Case
thumb150×150List thumbnails, small icons
medium600×600Listings, card images
large1200×1200Detail views, full-screen galleries
hero1920×800Hero banners, headers
avatar200×200User avatars, profile pics
card400×300Product cards, previews

Note: Without query params, images keep original dimensions (capped at 2048px max).

# Usage
https://cdn.example.com/path/image.jpg?preset=thumb
https://cdn.example.com/path/image.jpg?preset=hero

Query Parameters

ParameterTypeDefaultDescription
presetstring-Only way to resize - see presets table above
qnumber80Quality percentage (1-100)
fstringautoOutput format
fitstringinsideResize fit mode (used with presets)

Security: Custom w and h parameters are disabled to prevent cache pollution attacks. Use presets only.

Format Options (f)

ValueDescription
autoAuto-detect best format (WebP/AVIF if browser supports)
jpegForce JPEG output
webpForce WebP output
pngForce PNG output (preserves transparency)
avifForce AVIF output (best compression, newer browsers)

Fit Options (fit)

ValueDescription
insideResize to fit within dimensions (default, maintains aspect ratio)
coverResize to cover dimensions (crop overflow)
containSame as inside, with padding if needed
outsideResize to cover, allowing overhang
fillStretch to exact dimensions (ignores aspect ratio)

Examples

Thumbnails for List View

# 150x150 thumbnail, high quality
?preset=thumb&q=90

# Custom small square
?w=100&h=100&fit=cover&q=80

Product Cards

# Standard card size
?preset=card

# Custom card with WebP
?w=400&h=300&f=webp&q=85

Hero Images

# Full-width hero
?preset=hero

# Custom hero dimensions
?w=1920&h=600&fit=cover&q=85

Avatars

# Standard avatar
?preset=avatar

# Circular crop
?w=200&h=200&fit=cover&q=80

High-Quality Downloads

# Large, high-quality (for downloads/printing)
?preset=large&q=95

# Original quality, just format conversion
?q=100&f=webp

API Response Transformation

When IMAGE_CDN_URL is configured, the ImageCdnTransformInterceptor automatically transforms S3 URLs in API responses to CDN URLs.

Note: Transformed URLs return images at original dimensions (max 2048px) with format conversion. Use presets for smaller sizes (e.g., ?preset=medium for listings).

Before (S3 URL)

{
  "id": "123",
  "imageUrl": "https://pers.assets.dev.s3.eu-west-1.amazonaws.com/products/photo.jpg"
}

After (CDN URL)

{
  "id": "123",
  "imageUrl": "https://d3bznwycx2s7pk.cloudfront.net/products/photo.jpg"
}

Disabling Transformation

To disable automatic transformation, don't set IMAGE_CDN_URL in your environment.

SDK Integration

TypeScript/JavaScript

import { ImageCdnUrlBuilder } from '@pers/serverless-functions/infrastructure/interceptors';

const cdn = new ImageCdnUrlBuilder('https://d3bznwycx2s7pk.cloudfront.net');

// Using presets
const thumb = cdn.thumbnail('products/photo.jpg');
const large = cdn.large('products/photo.jpg');

// Custom options
const custom = cdn.build('products/photo.jpg', {
  width: 800,
  height: 600,
  quality: 85,
  format: 'webp',
  fit: 'cover',
});

Mobile SDK

// iOS Example
let cdnUrl = "https://d949acbs6mj2e.cloudfront.net"
let imagePath = "products/photo.jpg"
let thumbnailUrl = "\(cdnUrl)/\(imagePath)?preset=thumb"
// Android Example
val cdnUrl = "https://d949acbs6mj2e.cloudfront.net"
val imagePath = "products/photo.jpg"
val thumbnailUrl = "$cdnUrl/$imagePath?preset=thumb"

Environment Configuration

Add to your .env file:

# Enable CDN URL transformation
IMAGE_CDN_URL=https://d3bznwycx2s7pk.cloudfront.net

# Optional: Default preset for transformed URLs
IMAGE_CDN_DEFAULT_PRESET=medium

Environment Variables

VariableDescriptionExample
IMAGE_CDN_URLCDN base URL (enables transformation)https://d3bznwycx2s7pk.cloudfront.net
IMAGE_CDN_DEFAULT_PRESETDefault preset for auto-transformationmedium
AWS_S3_BUCKET_NAMES3 bucket name (for URL matching)pers.assets.dev

Performance

MetricValue
First request~200-500ms (Lambda cold start + processing)
Cached requests~10-50ms (CloudFront edge cache)
Cache duration1 year (immutable images)
CompressionUp to 90%+ reduction

Cache Headers

Cache-Control: public, max-age=31536000, immutable
X-Image-Optimized: true

Error Handling

HTTP CodeDescription
200Success - optimized image returned
404Image not found in S3
5xxProcessing error - falls back to original image from S3

Note: Invalid parameters are automatically clamped to valid ranges (e.g., w=5 becomes w=10, q=150 becomes q=100).

Architecture

┌──────────────┐     ┌─────────────────┐     ┌───────────────┐
│   Client     │────▶│   CloudFront    │────▶│  Lambda@Edge  │
│  (Browser)   │     │   (CDN Edge)    │     │  (us-east-1)  │
└──────────────┘     └─────────────────┘     └───────┬───────┘
                            │ cache                  │
                            ▼                        ▼
                     ┌─────────────────┐     ┌───────────────┐
                     │  Edge Cache     │     │   S3 Bucket   │
                     │  (31536000s)    │     │  (eu-west-1)  │
                     └─────────────────┘     └───────────────┘

Supported Formats

Input Formats

  • JPEG (.jpg, .jpeg)
  • PNG (.png)
  • WebP (.webp)
  • GIF (.gif) - animations preserved
  • AVIF (.avif)

Output Formats

  • JPEG (default for photos)
  • WebP (auto-detected for Chrome, Edge, Firefox)
  • AVIF (auto-detected for Chrome 85+, Firefox 93+)
  • PNG (when transparency required)

Troubleshooting

Images not optimizing

  1. Check IMAGE_CDN_URL is set in environment
  2. Verify image exists in S3 bucket
  3. Check CloudFront distribution is enabled

Cache not working

  1. CloudFront caches by full URL including query params
  2. Use consistent query param order
  3. Invalidate cache: aws cloudfront create-invalidation --distribution-id XXXXX --paths "/path/*"

Lambda errors

Check CloudWatch logs in us-east-1:

aws logs tail /aws/lambda/us-east-1.pers-image-optimizer-prod-imageOptimizer --follow