OptionalassetOptional URL prefix that the framework prepends to its built static
asset URLs (Next.js assetPrefix, Nuxt's app.buildAssetsDir).
When set, the L3 adds CloudFront behaviors at /<prefix>/_next/*
(or framework-specific pattern) so chunks/CSS/images load correctly.
Format: leading slash, no trailing slash. Examples: /shop-static,
/cdn, /foo/bar. Set to undefined (or omit) when the framework
uses the default same-origin asset URLs.
OptionalbaseOptional URL prefix that prefixes every routable URL on the deployed
site. Maps to Next.js basePath, Astro base, Nuxt app.baseURL.
When set, every CloudFront behavior pattern is prefixed and the bare
domain root issues a 308 redirect to /<basePath>/.
Format: leading slash, no trailing slash. Examples: /app, /docs.
Use assetPrefix for asset-only prefixing; basePath covers SSR
routes too.
OptionalbuildBuild ID for atomic deployments.
OptionalcacheCache infrastructure (provisioned if present)
Named compute resources
OptionalerrorStatic error pages emitted by the build (e.g. Next.js
output: 'export' writes 404.html from app/not-found.tsx).
When set, the L3 wires CloudFront CustomErrorResponses to serve
the named file at the original status code (404 → /404.html with
status 404), instead of the SPA fallback that maps every error to
/index.html with status 200. Typical entries:
{ 404: '/404.html' } { 404: '/404.html', 500: '/500.html' }
Static-only deploys without this field continue to use the SPA fallback (suitable for client-routed React apps).
OptionalheadersCustom response headers
OptionalimageImage optimization (separate Lambda if present)
OptionalinvalidationOVERRIDE for the CloudFront invalidation paths issued on every deploy,
AFTER the atomic KVS cutover. Most adapters leave this UNSET and let the
L3 pick the default (see below); set it only to customize the paths or to
opt out ([]).
Why an invalidation is needed at all — the stale-HTML→403 problem:
Atomic deploys write every object under a brand-new immutable
builds/<buildId>/ prefix, so there is nothing stale to invalidate, and
HTML served from S3 carries no-cache (the 3-tier Cache-Control split in
hosting_construct). So a PURE-STATIC deploy (no compute) needs no
invalidation — Astro/Nuxt static pages prerender to S3 and propagate on
the next request.
But ANY compute-backed deploy can edge-cache HTML that goes stale. The
shared SSR cache policy honors the origin's Cache-Control, so HTML
served by the compute origin with a long s-maxage is edge-cached keyed
on the VIEWER path (/about), NOT the build-id prefix. After a redeploy
that HTML still references the previous build's hashed assets
(_next/static/*, _nuxt/*, _astro/*), and the router rewrites those
asset requests to the CURRENT build prefix — which no longer contains
them → 403. This is NOT Next-specific:
s-maxage=31536000.routeRules cache.maxAge / swr / isr emit
s-maxage=N on compute-origin HTML (see nitro adapter).Cache-Control on the response.
The common trigger is "a compute origin serving cacheable HTML that
references build-prefixed hashed assets" — so the L3 scopes the
invalidation on hasCompute, not on the framework.Default (when this field is unset): the L3 issues ['/*'] for any deploy
with a compute origin, and nothing for pure-static deploys. The
invalidation is gated after the KvKeys cutover, so it only flushes the
previous build's cached pages — the new build's builds/<id>/... objects
were never cached, making /* effectively free. A compute app that emits
only no-store HTML still gets the invalidation, but it is a harmless
no-op. Set [] to opt out; set explicit patterns to narrow it.
OptionallifecycleAdapter-supplied S3 lifecycle rules for orphaned per-build data that lives outside the build prefix.
The default DeleteOldBuilds lifecycle on builds/<id>/ covers
everything under the build prefix. Some frameworks emit data
outside the build prefix that survives across builds and needs
its own expiration:
_next/data/<buildId>/... JSON files used by
getStaticProps fallbacks; older entries linger if the user
toggles output: modes.Each entry installs an S3 lifecycle rule expiring objects under
prefix after days. Adapter code knows where its framework
writes these files; the L3 just installs whatever the adapter
declares. Empty / undefined → no extra rules.
Days after object creation before expiration.
S3 key prefix to expire — e.g. _next/data/.
OptionalmiddlewareMiddleware (edge function if present)
OptionalredirectsRedirects
OptionalrewritesRewrites
Route behaviors (maps URL patterns to compute/static)
Static asset configuration
OptionalcacheControl?: stringCache-Control header for non-hashed assets (HTML, public/, etc.).
Defaults to public, max-age=0, must-revalidate so a redeploy
invalidates cached HTML on next request — required to avoid PWA
"brick" scenarios where a cached index.html references hashed
URLs that the new deploy already removed.
Path to static files directory
OptionalimmutablePaths?: string[]Glob patterns (relative to directory) of content-hashed asset
directories. Files matching these globs receive a long-lived,
immutable Cache-Control; everything else uses the short-lived
cache above. Adapters set this to the framework's hashed-output
dir(s):
Next.js / OpenNext: ['_next/static/*']
Astro: ['_astro/*']
Nuxt / Nitro: ['_nuxt/*']
When omitted, all assets receive the single cacheControl value
above (back-compat with adapters that don't yet declare hashed
paths).
OptionalnoCachePaths?: string[]Glob patterns (relative to directory) of files that must never
be cached. These receive Cache-Control: no-cache, no-store, must-revalidate. Use for runtime config files (e.g.
.blocks-sandbox/config.json) that change between deploys and
must never serve stale content even briefly.
OptionalspaFallback?: booleanWhether this static deploy is a single-page app (SPA) that relies on client-side routing, versus a multi-page site where each route is its own prerendered HTML file.
Controls how the CloudFront viewer-request function resolves extensionless URLs:
true (SPA): every navigation request (no file extension) is
rewritten to /index.html so the client-side router can handle
deep links. Missing paths serve index.html at HTTP 200.
Correct for Vite/React-Router/Vue-Router single-page apps.false (multi-page): each request resolves to its own
<path>/index.html (directory-index resolution). A request for
/about serves about/index.html, NOT the home page. Correct
for static-site generators (Astro static, Hugo, Eleventy) that
prerender every route to a separate HTML file.Set by the adapter, which is the only layer that knows the
framework's routing model (the L3 is framework-blind). When
omitted, the L3 falls back to a heuristic: SPA mode when the deploy
has no compute AND no errorPages (preserved for back-compat with
adapters that don't yet declare this). Ignored when the manifest
has compute resources (SSR), since routing then flows through the
compute origin rather than static index resolution.
Framework-agnostic deployment manifest.
Produced by framework adapters (Next.js/OpenNext, SvelteKit, Astro). Consumed by the L3 HostingConstruct.
The L3 NEVER knows which framework produced this manifest.