feat: support build-time prerendering of routes#3766
Open
bartlomieju wants to merge 1 commit into
Open
Conversation
Add `prerender` option to `RouteConfig` that generates static HTML at build time. Routes marked with `prerender: true` are rendered during the build step and served as static files at runtime, bypassing the route handler entirely. For dynamic routes, `prerender` accepts a function that returns an array of param objects to enumerate which paths to generate. Closes #3555 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
lunadogbot
suggested changes
May 12, 2026
Contributor
lunadogbot
left a comment
There was a problem hiding this comment.
MemoryBuildCache.loadedFsRoutes, the optional contentType on addProcessedFile, and the pathname === "/" || removal in static_files.ts:31 are all minimal and consistent with the rest of the cache.
One correctness blocker worth fixing before this ships:
substituteParamsinpackages/fresh/src/dev/prerender.ts:86callsresult.replace(":" + key, value)— substring match, first occurrence only./:id/:identifierwith{ id: "X", identifier: "Y" }becomes/X/Xentifierbecause:identifierstarts with:id. Same hazard for:slugvs:slugify, etc. Use a regex with a word boundary (:slug(?![A-Za-z0-9_])), or split on/and match segments exactly so:foo*and:fooare both handled cleanly.
- nit:
encoder.encode(await res.text())round-trips bytes through a decode/encode;new Uint8Array(await res.arrayBuffer())is one less pass. - nit: tests cover
:slugand static routes but not catch-all[...slug](pattern becomes:slug*) or route groups ((group)). The:slug*branch insubstituteParamsis untested. - nit:
fs_crawl.ts:77matches the literal string"prerender"anywhere in source, including comments and identifiers — same shape as the existingrouteOverridecheck, so it's consistent, but worth a comment noting the heuristic.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
prerenderoption toRouteConfigfor generating static HTML at build timeprerender: trueare rendered during the build and served as static files at runtime — zero rendering cost per requestprerender: () => [{ slug: "foo" }, { slug: "bar" }]to enumerate pathsUsage
Closes #3555
Current limitations
MemoryBuildCache(used in tests and Deno Deploy).DiskBuildCachesupport (disk snapshots) and Vite plugin integration are not yet implemented.App.fsRoutes()app, so custom middleware state (auth, sessions) is not available during prerender. At serve time, middlewares are bypassed entirely since the static files middleware intercepts first.text/html; charset=UTF-8content type explicitly, since route pathnames like/abouthave no file extension for auto-detection.What's left (follow-up PRs)
server_snapshot.tsproduction branch)DiskBuildCachesupport — prerender beforeflush()so HTML is included in the disk snapshotprerenderto route config docs, add a "Static Site Generation" page under Advanced_app.tsxand_layout.tsxwrappers via the temp appDogfooding
Attempted to dogfood with the
www/docs site, but its routes use dynamic handlers (query params, user-agent detection for Deno CLI redirects) that aren't suitable for prerendering. The feature is best validated on pure-static pages like/about,/pricing,/docs/*with content loaded at build time.Test plan
Prerender - static route—/and/aboutwithprerender: trueproduce HTML served as static filesPrerender - dynamic route with path function—[slug]route withprerender: () => [...]generates correct pagesPrerender - skips dynamic route with prerender: true— warns and skips whenprerender: trueis used on a[param]route🤖 Generated with Claude Code