For a site holding both editorial images committed to the repository and images uploaded by users, how would you decide between generating image derivatives at build time and generating them at request time through an image CDN?
answer
- is the image set knowable at build?
- build minutes versus metered transforms
- uploads arrive after deployment
- hybrid, split by enumerability
basics
~20 sBuild-time generation fits a known, bounded set of images and yields plain static files with no runtime dependency; request-time generation is required for content that arrives after deployment. Most real sites end up hybrid, split on whether the image set is enumerable at build.
solid answer
~60 sThe deciding question is whether the set of images is **knowable when you build**. Editorial images in the repository are: you can enumerate them, generate every variant ahead of time, and ship plain static files that any host can serve with long-lived immutable caching, no per-request cost, and no vendor in the request path. User uploads are not: they arrive after the build, so the only options are request-time transformation or a background job that becomes a bespoke image service. That pushes most real sites to a hybrid — build-time for the bounded editorial set, an image CDN for the unbounded user-generated tail. The costs to weigh out loud are build duration, which grows with images times variants and needs a persistent cache to stay tolerable; cold-miss latency and metered transformations on the request-time side; and lock-in, since vendor URL syntax spreads through templates unless every image URL is generated by one helper. I would also let the *criticality* of the image break ties: the hero on the landing page is worth pre-generating and warming regardless of which pipeline the rest of the site uses.
go deeper
Know the basic split: images that exist in the repository can be converted ahead of time, while images users upload after release must be handled when they are requested.
Contrast the two concretely — static files with immutable caching and no runtime dependency, versus on-demand transformation with a cold-miss cost — and name what makes builds slow.
Show operational judgment: a persistent encode cache to keep CI honest, warming the hero derivative after deploy, and monitoring miss rate and transformation spend on the request-time side.
Structure the decision from the inputs and keep it reversible — split by whether the set is enumerable, price slow builds against a metered runtime dependency, and centralize URL generation so the choice can be revisited cheaply.
## Two pipelines, one question Both pipelines end in the same place — correctly sized, modern-format images at the edge. They differ in *when* the encode happens and *who owns the risk*. **Build time:** a step in CI reads each source image, produces every variant you configured, and emits real files. The deployed artifact contains them. Serving is then a solved problem: static files, content-addressed names, long `max-age`, no compute in the request path. **Request time:** one master sits at an origin, and an image CDN produces variants when they are first requested and caches them. ## What build time buys - **No runtime dependency.** The images are files. If your image vendor has an outage, nothing happens to you. - **Deterministic output.** The bytes were produced once, reviewed if you like, and cannot silently change because a provider updated an encoder. - **No metered transformations.** The cost is CI minutes, which you already pay for and can measure. - **Trivial caching.** Content-hashed filenames plus immutable caching is the easiest caching story that exists — no `Vary`, no key normalization, no cold-miss cliff. ## What build time costs - **Build duration scales with images times variants.** Encoding AVIF in particular is slow. A few hundred images across a handful of widths and two formats turns into thousands of encodes, and re-doing them on every CI run is intolerable. This is survivable only with a **persistent cache keyed by source hash plus transform**, so unchanged images are never re-encoded — and that cache becomes something you now operate. - **The variant matrix is fixed at build.** Adding a width or a format means a rebuild and redeploy of the whole set. - **It cannot serve what does not exist yet.** This is the hard boundary. ## What request time buys - **Unbounded and unknown inputs work.** User uploads, images pulled from a CMS after deploy, or a catalogue too large to pre-render are all fine. - **Policy is changeable without a rebuild.** Lowering quality site-wide, or enabling a new format, is a configuration change that takes effect on the next miss. - **You only produce what is actually requested.** A long-tail catalogue where 90% of items are rarely viewed never pays for the variants nobody asked for. ## What request time costs - **Cold-miss latency**, landing on a real visitor, and concentrated exactly where it hurts — new pages, new campaigns, long-tail content. - **Metered spend** on transformations and derivative storage, which turns cache-key discipline into a budget line and abuse into an availability problem. - **A dependency in the critical path.** Provider outage means missing images. - **Lock-in through URL syntax.** Parameter dialects differ per vendor; if templates write them by hand, migration means touching every template. ## The hybrid, and how to split it Most mature sites run both, and the honest split is not "editorial versus product" but **enumerable versus not**: - Anything you can list at build — marketing pages, the design system, blog assets — goes through the build pipeline with a persistent encode cache. - Anything that arrives later — uploads, syndicated content, catalogue images managed outside the repo — goes through the image CDN. On top of that, apply a criticality override. The single largest image on your highest-traffic entry point deserves special treatment whichever pipeline owns it: pre-generate it, or warm its exact derivative URLs after deploy so no visitor pays the miss. ## Keeping the decision reversible Whichever way you go first, you will likely revisit it, so build the exit now: - **One URL helper.** Every image URL in the codebase comes from a single function that takes an image reference and a preset name. Swapping providers, or moving one class of images from one pipeline to the other, becomes one file. - **Named presets, not free-form numbers.** Presets are portable across pipelines and bound the variant set on both sides. - **Stable, versioned source paths** so a changed image is a new URL, which keeps both pipelines honest about cache invalidation. ## How I would present the decision Start from the inputs, not the tooling: are the images enumerable at build, how many are there, and how often do they change? Then price the two failure modes against each other — a slow build that delays every deploy versus a metered runtime dependency with a cold-start cliff. Then decide per class of image rather than for the whole site, and write down the criticality exception for the hero. An interviewer at this level is listening for that structure, and for whether you noticed that "user uploads" alone already forecloses the pure build-time answer.
- What makes a build-time image pipeline stay tolerable as the image count grows?A persistent cache keyed by source-file hash plus transformation parameters, shared across CI runs. Unchanged images are then never re-encoded and only new or edited ones cost time. Without it, every build re-encodes everything and AVIF alone can add many minutes. The tradeoff is that the cache is now infrastructure you own and occasionally have to debug.
- If you adopt an image CDN, how do you avoid its URL syntax spreading through the codebase?Route every image URL through one helper that takes an image reference and a named preset and returns a URL. Templates never write parameters by hand. The vendor's dialect then lives in a single module, so switching providers, changing the width ladder, or moving a class of images to a build-time pipeline is one edit rather than a codebase-wide search.
- Which image would you pre-generate even on a site that otherwise transforms everything at request time?The largest image on your highest-traffic entry page — typically the landing hero. It is the one most likely to determine the page's perceived load time, and it is the worst possible place for a visitor to pay a cold-derivative miss. Either ship it as a static file or warm its exact derivative URLs immediately after each deploy.
saying these in an interview costs you the question
- Claims build-time generation can serve user uploads
- Ignores that build time scales with images times variants
- Treats metered transformations as a rounding error
- Picks one pipeline for the whole site without splitting by input