Skip to content

feat(build): list route rules at the end of the build - #1664

Draft
atinux wants to merge 1 commit into
feat/client-bundle-summaryfrom
feat/build-route-rules
Draft

atinux wants to merge 1 commit into
feat/client-bundle-summaryfrom
feat/build-route-rules

Conversation

@atinux

@atinux atinux commented Nov 8, 2026 •

Copy link
Copy Markdown
Member

Written by an AI agent on behalf of @atinux. @atinux has not reviewed it yet.

Stacked on #1663 (client bundle summary), which is stacked on #1662 (quieter server build). Review those first; this PR only adds the last commit.

At the end of nuxt build there is no easy way to see which routes are prerendered, cached, client-only, redirected or proxied. Rules come from nuxt.config, from pages (defineRouteRules) and from modules, so the config file alone doesn't tell you.

What changed

  • nuxt build prints a Route rules table (route, rules) after the client bundle summary.
  • The rules are read from the Nitro instance (nitro:init hook) after the build. It is the only place that has page rules and module rules: nuxt.options.routeRules lacks page rules in production builds, and kit.tryUseNitro() returns nothing once the build has finished.
  • Nitro's resolved rules are turned back into short labels: prerender, ssr: false, isr 600s, swr 3600s, cache: false, redirect → /x (307), proxy → url, cors, headers: <names> and middleware. Unknown keys are listed as they are.
  • Works with Nitro 2 and Nitro 3. They resolve rules differently, so both are read:
    • Nitro 3 keeps only cache: { swr, maxAge } for swr.
    • Nitro 3 names the redirect code status, where Nitro 2 uses statusCode.
    • Nitro 3 leaves cors: {} without expanding it into headers.
  • Nuxt's own entries are hidden: /__nuxt_error, the /** ssr: true default, the cache headers under app.buildAssetsDir, and the _payload.json copies of cached routes. Nuxt renames unnamed page segments to /:_2; they are shown as /* again.
  • Routes are sorted and capped at 20 rows with +N more routes, like the chunk list in feat(build): summarise the client bundle at the end of nuxt build #1663. Nothing is printed when the app has no rules of its own.

Videos

Both apps use the same nuxt.config, with 7 route rules and experimental.inlineRouteRules, plus defineRouteRules({ prerender: true }) in pages/blog/[slug].vue. Before is #1663's head (2c6edf6), after is this branch. Recorded with asciinema in a 110×40 terminal and rendered with agg. Pauses are capped at 1.5s, so the clips run faster than the real builds.

Nitro 2 (Nuxt 4.6.2, Nitro 2.13.5)

Before After
nuxt build with Nitro 2 before nuxt build with Nitro 2 after

Nitro 3 (Nuxt 5.0.0-2610281032-c0c2b8f nightly, Nitro 3.0.260903-beta)

Before After
nuxt build with Nitro 3 before nuxt build with Nitro 3 after

Both builds exit 0 and print the same table:

Route rules  8 routes

Route         Rules
/             prerender
/admin/**     ssr: false
/api/**       cors, headers: x-api
/blog/*       prerender
/blog/**      swr 3600s
/old          redirect → /new (307)
/products/**  isr 600s
/proxy/**     proxy → https://example.com/**

The repo playground has no route rules, and its build prints no table.

Tests

test/unit/utils/route-rules.spec.ts checks the table against nitro.options.routeRules dumped from real Nitro 2 and Nitro 3 builds. It also covers the row cap and the empty case. The full suite passes (env -u NO_COLOR TERM=xterm-256color pnpm exec vitest run packages: 155 files, 2187 tests), as do eslint and tsc --noEmit.

Details and open questions

  • In an interactive terminal, clack adds its own spacer between messages, so there are two gutter lines between blocks (visible in the videos). The client bundle summary above has the same gap. The non-TTY output is spaced correctly.
  • The table doesn't say where each rule came from (config, page or module). Nuxt merges them before Nitro sees them, so this would need Nuxt to keep that information.
  • This is a prototype, so it isn't behind a flag. It may need one (or --log-level) for apps with many rules.
  • The timing line wraps at 110 columns; that comes from feat(build): quieter Nitro server build output #1662's phase names, not from this PR.

ELI5

After building, Nuxt now lists every page pattern that has special handling, such as "built ahead of time", "cached for an hour" or "sent to another URL". You can check it matches what you meant without reading through config files and pages.

@atinux
atinux force-pushed the feat/client-bundle-summary branch from 18602f5 to 38d07fe Compare November 8, 2026 08:33
@atinux
atinux force-pushed the feat/build-route-rules branch from c7c87ac to 0b40141 Compare November 8, 2026 08:35
@atinux
atinux force-pushed the feat/client-bundle-summary branch from 38d07fe to 5ab9fa8 Compare November 8, 2026 08:45
@atinux
atinux force-pushed the feat/build-route-rules branch from 0b40141 to 7282bdf Compare November 8, 2026 08:47
@atinux
atinux force-pushed the feat/client-bundle-summary branch from 5ab9fa8 to aba7cd5 Compare November 8, 2026 08:48
@atinux
atinux force-pushed the feat/build-route-rules branch from 7282bdf to 2951767 Compare November 8, 2026 08:50
@atinux
atinux force-pushed the feat/client-bundle-summary branch from aba7cd5 to 71dc0ba Compare November 8, 2026 08:57
@atinux
atinux force-pushed the feat/build-route-rules branch from 2951767 to b3afdc7 Compare November 8, 2026 08:58
@atinux
atinux force-pushed the feat/client-bundle-summary branch from 71dc0ba to 2c6edf6 Compare November 8, 2026 09:14
@atinux
atinux force-pushed the feat/build-route-rules branch 3 times, most recently from ba511a6 to 0e69230 Compare November 8, 2026 09:23
@atinux
atinux force-pushed the feat/client-bundle-summary branch from 2c6edf6 to 893a812 Compare November 9, 2026 22:38
@atinux
atinux force-pushed the feat/build-route-rules branch from 0e69230 to 3738578 Compare November 9, 2026 22:40
@atinux
atinux force-pushed the feat/client-bundle-summary branch from 893a812 to eb95914 Compare November 10, 2026 11:36
@atinux
atinux force-pushed the feat/build-route-rules branch from 3738578 to 128bc02 Compare November 10, 2026 11:38
@atinux
atinux force-pushed the feat/client-bundle-summary branch from eb95914 to a696a61 Compare November 10, 2026 11:42
@atinux
atinux force-pushed the feat/build-route-rules branch from 128bc02 to 8744da0 Compare November 10, 2026 11:44
@atinux
atinux force-pushed the feat/client-bundle-summary branch from a696a61 to b474ee8 Compare November 10, 2026 11:48
@atinux
atinux force-pushed the feat/build-route-rules branch from 2f6be04 to 830cd25 Compare November 10, 2026 11:50

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant