GioJSdocs
On this page

[images]

The /_gio/image optimizer behind <GioImage>: widths, quality, output formats, remote sources and the limits on what one image may cost.

gio.toml
[images]
allowed_widths = [640, 828, 1080, 1200, 1920]
quality = 80
formats = ["webp"]

[[images.remote_patterns]]
hostname = "images.example.com"
pathname = "/uploads/*"

Image Optimization shows how <GioImage> uses these settings.

Reference

KeyDefaultDescription
enabledbooleantrueRun the optimizer. Turn it off behind an image CDN, or to have no CPU-heavy endpoint: every image is then served as the file it names, at full size, without a srcset.0 / false / empty: /_gio/image is a 404; <GioImage> renders its plain src
allowed_widthsinteger[][16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840]The only widths the optimizer resizes to (any other w is a 400), and the <GioImage> srcset candidates. Order does not matter; 0 entries are ignored for srcsets.
qualityinteger75Default output quality, 1 to 100. 0 is used as 1 and 101 to 255 as 100; a larger number is a startup error (invalid value: integer `300`, expected u8).<GioImage quality> and the q parameter override it per image.
formatsstring[]["avif", "webp"]Modern formats to serve when the browser's Accept names them, in order of preference: "avif", "webp" (or "image/avif", "image/webp"). Everything else gets JPEG. AVIF is several times slower to encode than WebP; leave it out to save CPU.0 / false / empty: []: always JPEG
remote_patternstable[][]Remote sources the optimizer may fetch, one [[images.remote_patterns]] table each (keys below). None by default: a remote src is a 403.
disk_max_bytesinteger536870912Size cap of the optimized-image disk cache (512 MiB) under .gio/cache/images; past it the oldest files are deleted. GIO_IMAGE_CACHE_DIR moves the directory.0 / false / empty: No size bound
max_remote_bytesinteger20971520Largest remote source downloaded, in bytes (20 MiB). A bigger one is a 400.0 / false / empty: Unlimited. Warns.
remote_timeout_secsinteger30Deadline for downloading a whole remote source. The 5-second connect timeout applies either way.0 / false / empty: No deadline. Warns.
max_source_dimensioninteger10000Largest source width or height decoded, in pixels. A larger source is a 500: a small file can declare huge dimensions.0 / false / empty: Unlimited. Warns.
max_decode_bytesinteger268435456Most memory decoding one source may allocate (256 MiB).0 / false / empty: Unlimited. Warns.

remote_patterns

KeyDefaultDescription
protocolstring"https""https" or "http"; must equal the source's scheme.
hostname (required)string-An exact host (images.example.com), *.example.com (exactly one more label), or **.example.com (any depth, example.com itself included). An IP address only matches an exact entry, never a wildcard.
pathnamestring-An exact path, or a prefix with a trailing * (/uploads/*). Unset: any path.

Behavior

/_gio/image takes src (a public/ file as served, /hero.png or /public/hero.png, or an allowed remote URL), w (an allowed width), q (1-100) and f (avif, webp, jpeg, png; a modern format not in formats falls back to negotiation).

StatusWhen
200The image, Cache-Control: public, max-age=31536000, immutable, Vary: Accept (private, no-cache for a file a guard admitted this visitor to).
400A width not in allowed_widths, a q outside 1-100, a remote source over max_remote_bytes.
403A remote source no pattern allows, a redirect from a remote source, a path outside public/, a file a guard denies this visitor.
404No src, a missing file, or the optimizer is off.
500A source that fails to download or decode, or exceeds the decode limits.

The server hands enabled, the sorted widths and the quality to the worker in GIO_IMAGE_CONFIG, so <GioImage> renders only srcsets the optimizer accepts. Those settings are part of the deployment id: changing them drops persisted pages. [[rate_limits]] rules apply to /_gio/image, the only built-in endpoint they cover.

Startup warnings

While the optimizer is on, each limit lifted to 0 logs one line:

WhenStartup warning
max_remote_bytes = 0[images] max_remote_bytes = 0: remote sources of any size are downloaded into memory
remote_timeout_secs = 0[images] remote_timeout_secs = 0: a slow remote source holds its request open indefinitely
max_source_dimension = 0[images] max_source_dimension = 0: a small file declaring huge dimensions can exhaust memory and CPU
max_decode_bytes = 0[images] max_decode_bytes = 0: decoding one source may allocate any amount of memory

enabled = false logs image optimizer disabled ([images] enabled = false): /_gio/image is not routed at info level.

Examples

Images from a CMS

gio.toml
[[images.remote_patterns]]
hostname = "**.ctfassets.net"

[[images.remote_patterns]]
hostname = "cdn.sanity.io"
pathname = "/images/*"

WebP only, to save CPU

gio.toml
[images]
formats = ["webp"]

An image CDN in front

gio.toml
[images]
enabled = false        # <GioImage> renders plain src; the CDN resizes

Good to know

  • Optimized images are cached in memory and on disk by source, width, quality and format; a changed source file under the same URL keeps its old variants until they are evicted. Give edited images new names.
  • Unknown formats are a startup error (unknown variant `png`, expected one of `avif`, `image/avif`, `image/webp`, `webp`): PNG and JPEG are always available through f=.
  • A remote_patterns entry that could never match is a startup error naming its line: a protocol other than "https" or "http" (lowercase), an empty hostname or one with a scheme, path, port or uppercase letters, and a pathname that does not start with / (pathname "uploads/*" must start with '/', or it matches no path - did you mean "/uploads/*"?).
  • In a static export there is no optimizer: every image renders its plain src.

Not configurable

  • Path traversal checks. A local src must resolve (symlinks included) to a file inside public/.
  • Redirect blocking. A remote source that answers with a redirect is refused (403): the redirect target was never checked against remote_patterns.
  • Guard enforcement. A local file is held to the [[guards]] of both URLs it is served at, so the optimizer cannot be used to read a guarded file.

Version history

VersionChanges
v0.1.0-beta.8Added enabled, remote_timeout_secs, max_source_dimension and max_decode_bytes; formats is honored (it also bounds f=). max_remote_bytes = 0 means unlimited (it used to reject every remote image). Lifted limits log a startup warning.
v0.1.0-beta.6remote_patterns are matched on the parsed URL, wildcards match only domains, and pathname is enforced. Fixed decode limits (10000 px, 256 MB).
v0.1.0-beta.5Added disk_max_bytes and max_remote_bytes.
v0.1.0-beta.1Introduced with allowed_widths, quality and remote_patterns.