Image Transformations

Anvil ships an in-process image pipeline so common transforms (resize, format conversion, quality re-encode) don't need an external service. The pipeline runs on cache miss and writes the result to a content-addressed cache so repeated requests are zero copies.

Two endpoints

RouteAuth
/storage/v1/render/image/public/{bucket}/{path}None (bucket must be public)
/storage/v1/render/image/authenticated/{bucket}/{path}Session-bound, honours RLS
/storage/v1/render/image/sign/{bucket}/{path}Mint a signed render URL (transform baked into token)

Parameters

ParamTypeNotes
widthu32Target width in pixels
heightu32Target height in pixels
resizecover | contain | fillFit policy
formatwebp | jpeg | png | avifOutput encoder
qualityu32 1..100Encoder quality

Examples

# 200x200 webp thumbnail
http://host/storage/v1/render/image/public/avatars/alice.png?width=200&height=200&resize=cover&format=webp

# Signed render URL with transform sealed into the token.
curl -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "expires_in": 3600,
    "transform": {"width": 200, "height": 200, "format": "webp"}
  }' \
  http://localhost:7474/storage/v1/render/image/sign/avatars/alice.png

Cache

Variants are cached on disk under {cache_dir}/{source_hash}/{params_hash}. Configure cache size and limits in [file_storage.image_transforms]:

[file_storage.image_transforms]
cache_dir = "./data/image_cache"
max_cache_size = "2GiB"
image_max_dimension = 4096
allowed_formats = ["webp", "jpeg", "png", "avif"]

Limits

Requests for dimensions over image_max_dimension return 400 - protects the renderer from accidental memory blow-ups. Disallowed output formats also 400.