Skip to content

Version adapter routing for Pages API routes - #97366

Draft
timneutkens wants to merge 1 commit into
canaryfrom
codex/versioned-i18n-pages-api-routing
Draft

timneutkens wants to merge 1 commit into
canaryfrom
codex/versioned-i18n-pages-api-routing

Conversation

@timneutkens

Copy link
Copy Markdown
Contributor

Summary

Introduce routing manifest v2 for the adapter build-complete contract and restore canonical routing for dynamic Pages API routes in i18n applications.

  • Emit routing.version: 2 for normal and static-export builds, and document that unversioned manifests have implicit v1 semantics.
  • Keep dynamic Pages API matchers and destinations under /api, without nextLocale, while ordinary dynamic Pages routes remain localized.
  • Restore the focused i18n assertions and extend the adapter contract tests for the new version field.

This PR intentionally depends on adapter-vercel #103 being released and synced into the Vercel builder first. An old adapter receiving routing manifest v2 is unsupported; rollout order is the compatibility mechanism for that pairing.

Verification

  • pnpm --filter=next build
  • NEXT_TEST_PREFER_OFFLINE=1 pnpm test test/production/adapter-config-i18n test/production/adapter-config (3 suites passed, 6 tests passed, 1 skipped)
  • Prettier and ESLint checks on all changed files

@github-actions

github-actions Bot commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

Stats from current PR

✅ No significant changes detected

📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 814ms 813ms ✓ ▁▅█▅▅
Cold (Ready in log) 799ms 794ms ✓ ▁▄█▅▄
Cold (First Request) 1.282s 1.269s ✓ ▁▅█▅▄
Warm (Listen) 813ms 814ms ✓ ▁████
Warm (Ready in log) 789ms 810ms ✓ ▁▆▅▆▅
Warm (First Request) 1.249s 1.304s ✓ ▁▅▂▅▃
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 810ms 811ms ✓ █▁█▁▁
Cold (Ready in log) 779ms 781ms ✓ ▅▂▅▁▅
Cold (First Request) 3.227s 3.232s ✓ ▄▁▄▁▄
Warm (Listen) 810ms 810ms ✓ ▇▅▇▁▅
Warm (Ready in log) 785ms 783ms ✓ ▁▃▅▁▅
Warm (First Request) 3.302s 3.314s ✓ ▁▂▄▂▄

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 5.790s 5.670s ✓ ▁▇█▇█
Cached Build 3.027s 2.928s ✓ ▁▄█▃▃
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 23.678s 23.582s ✓ ▃▂▆▁▆
Cached Build 23.876s 23.682s ✓ ▂▄▆▁▄
node_modules Size 554 MB 554 MB ✓ ██▁▁▁
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
017_4moyv5m34.js gzip 117 B 117 B ✓
050icza-xjz0i.js gzip 5.73 kB N/A -
05jocc85-b73_.js gzip 341 B N/A -
0cz1d0mv5g_q7.js gzip 39.4 kB 39.4 kB ✓
0e5lgz-xcf6ln.js gzip 273 B 273 B ✓
0enhddgqs2dl-.js gzip 265 B 265 B ✓
0h34mejwa_7pd.js gzip 354 B 354 B ✓
0rci1f3or1a19.js gzip 13.3 kB N/A -
0w853zxni3ro0.js gzip 1.36 kB N/A -
19gb-1_5udxfb.js gzip 13.2 kB N/A -
1elt1qium-r2m.css gzip 115 B 115 B ✓
1j69gdzx96ry9.js gzip 5.91 kB N/A -
1m5vdnlf0deiv.js gzip 411 B 411 B ✓
1nigpy_mr0xvj.js gzip 339 B N/A -
1p0l8mn2wz5f2.js gzip 1.97 kB N/A -
1p7che5q-whyo.js gzip 117 B N/A -
1sqoyy39jpgkq.js gzip 121 B 121 B ✓
1tf1phijqlx9j.js gzip 220 B 220 B ✓
2b05_424u1zq-.js gzip 120 B N/A -
2c1v76a5-ve3u.js gzip 71.6 kB N/A -
2f1u17u5c8iny.js gzip 8.79 kB N/A -
2ixp3xn2_vz0r.js gzip 3.57 kB N/A -
2kci0vnt-49o-.js gzip 113 B 113 B ✓
2s60hgv8qgm1c.js gzip 65.6 kB N/A -
2sxgl_rcrrn_p.js gzip 399 B N/A -
2vst0p6zpfrr_.js gzip 7.53 kB N/A -
2vt62i17bhbdu.js gzip 2.35 kB N/A -
3-57trblvs1hc.js gzip 155 B N/A -
342di-crrg9kq.js gzip 119 B N/A -
36-p0_enxkb2k.js gzip 47 kB N/A -
36hfc2_979aw2.js gzip 119 B N/A -
38wfp6jjrrdfm.js gzip 131 B 131 B ✓
3dl1ilk37-30g.js gzip 117 B N/A -
3kvxagoobts7h.js gzip 117 B N/A -
3r0475panhk6m.js gzip 123 B N/A -
3s0i-weykgzrt.js gzip 125 B N/A -
3wijk2ywqgsv9.js gzip 2.52 kB N/A -
41u5s3oe2-erp.js gzip 2.29 kB N/A -
turbopack-0d..9ejy.js gzip 3.74 kB 3.74 kB ✓
02zc7sqlpqxn3.js gzip N/A 119 B -
0jwho9fkrb_t3.js gzip N/A 2.29 kB -
0longconn5mlm.js gzip N/A 123 B -
0p4l3ozbez2cz.js gzip N/A 2.35 kB -
0skdm-9rpid8g.js gzip N/A 117 B -
0wslrlyk8d3lb.js gzip N/A 117 B -
0wv-h56sz83wn.js gzip N/A 120 B -
137xup2t69ovc.js gzip N/A 1.97 kB -
1fk10s3m1oecx.js gzip N/A 400 B -
1g60xde_dv17t.js gzip N/A 8.79 kB -
1uzv47btzam64.js gzip N/A 5.73 kB -
20qhkyyj2_tla.js gzip N/A 116 B -
2imyufe18bsb7.js gzip N/A 1.36 kB -
2mr-6hunyw7uo.js gzip N/A 7.53 kB -
2nsrcvgnlgkby.js gzip N/A 3.56 kB -
2p4n3-8-xixh_.js gzip N/A 341 B -
34knadd6wu9qg.js gzip N/A 119 B -
39jq2b6t6z6up.js gzip N/A 339 B -
3a9a9tvkag_-j.js gzip N/A 2.52 kB -
3b4-wgmojlaav.js gzip N/A 71.7 kB -
3be8e3ccm9e51.js gzip N/A 5.91 kB -
3nhnanx_3z6fp.js gzip N/A 65.6 kB -
3skgwg3_u6i_e.js gzip N/A 13.2 kB -
3t121tj-h0kbm.js gzip N/A 125 B -
3tt4y5c9oeg16.js gzip N/A 47 kB -
3wjy00evyxo9u.js gzip N/A 152 B -
3y9tus7kb5su0.js gzip N/A 13.3 kB -
Total 300 kB 300 kB ⚠️ +6 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 1.02 kB 1.02 kB ✓
Total 1.02 kB 1.02 kB ✅ -2 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 847 B 848 B ✓
Total 847 B 848 B ⚠️ +1 B
Build Cache
Canary PR Change
00000001.sst gzip 12.3 MB 14.7 MB 🔴 +2.38 MB (+19%)
00000002.sst gzip 14.3 MB 14.4 MB 🔴 +41.6 kB (+0%)
00000003.sst gzip 15.2 MB 13.7 MB 🟢 1.46 MB (-10%)
00000004.sst gzip 13.4 MB 12.5 MB 🟢 952 kB (-7%)
00000005.sst gzip 2.8 MB 10.2 MB 🔴 +7.37 MB (+264%)
00000006.sst gzip 10.2 MB 2.8 MB 🟢 7.38 MB (-73%)
00000007.sst gzip 59 B 59 B ✓
00000008.meta gzip 89 B 89 B ✓
00000009.meta gzip 298 kB 298 kB ✓
00000010.meta gzip 298 kB 298 kB ✓
00000011.meta gzip 298 kB 298 kB ✓
00000012.sst gzip 53.6 kB 51.6 kB 🟢 1.94 kB (-4%)
00000013.sst gzip 1.85 MB 1.85 MB 🔴 +5.64 kB (+0%)
00000014.sst gzip 59 B 59 B ✓
00000015.meta gzip 116 B 116 B ✓
00000016.meta gzip 328 kB 328 kB ✓
00000017.meta gzip 408 kB 407 kB ✓
00000018.sst gzip 54.5 kB 52.4 kB 🟢 2.09 kB (-4%)
00000019.sst gzip 1.4 MB 1.41 MB 🔴 +8.15 kB (+1%)
00000020.sst gzip 59 B 59 B ✓
00000021.meta gzip 116 B 116 B ✓
00000022.meta gzip 328 kB 328 kB ✓
00000023.meta gzip 374 kB 374 kB ✓
00000024.sst gzip 54.6 kB 52.5 kB 🟢 2.11 kB (-4%)
00000025.sst gzip 1.39 MB 1.41 MB 🔴 +16.1 kB (+1%)
00000026.sst gzip 59 B 59 B ✓
00000027.meta gzip 116 B 116 B ✓
00000028.meta gzip 328 kB 328 kB ✓
00000029.meta gzip 374 kB 374 kB ✓
00000030.sst gzip 53.6 kB 51.8 kB 🟢 1.81 kB (-3%)
00000031.sst gzip 1.39 MB 1.41 MB 🔴 +16.1 kB (+1%)
00000032.sst gzip 59 B 59 B ✓
00000033.meta gzip 116 B 116 B ✓
00000034.meta gzip 328 kB 328 kB ✓
00000035.meta gzip 374 kB 374 kB ✓
00000036.sst gzip 54.4 kB 52.5 kB 🟢 1.92 kB (-4%)
00000037.sst gzip 1.39 MB 1.41 MB 🔴 +16.1 kB (+1%)
00000038.sst gzip 59 B 59 B ✓
00000039.meta gzip 116 B 116 B ✓
00000040.meta gzip 328 kB 328 kB ✓
00000041.meta gzip 374 kB 374 kB ✓
CURRENT gzip 94 B 94 B ✓
LOG gzip 678 B 664 B 🟢 14 B (-2%)
Total 80.4 MB 80.4 MB ⚠️ +54.8 kB

📦 Webpack

Client

Main Bundles
Canary PR Change
3322-HASH.js gzip 66.1 kB N/A -
4191.HASH.js gzip 169 B N/A -
7920-HASH.js gzip 4.67 kB N/A -
9784-HASH.js gzip 5.63 kB N/A -
b1ad9f4c-HASH.js gzip 63.5 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB ✓
main-app-HASH.js gzip 254 B 253 B ✓
main-HASH.js gzip 40.2 kB 40.2 kB ✓
webpack-HASH.js gzip 1.68 kB 1.68 kB ✓
3577.HASH.js gzip N/A 168 B -
578-HASH.js gzip N/A 66.2 kB -
8590-HASH.js gzip N/A 5.61 kB -
9750-HASH.js gzip N/A 4.68 kB -
a8984546-HASH.js gzip N/A 63.5 kB -
Total 242 kB 242 kB ⚠️ +29 B
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB ✓
Total 39.4 kB 39.4 kB ✓
Pages
Canary PR Change
_app-HASH.js gzip 194 B 193 B ✓
_error-HASH.js gzip 181 B 182 B ✓
css-HASH.js gzip 334 B 331 B ✓
dynamic-HASH.js gzip 1.81 kB 1.81 kB ✓
edge-ssr-HASH.js gzip 255 B 253 B ✓
head-HASH.js gzip 349 B 351 B ✓
hooks-HASH.js gzip 382 B 384 B ✓
image-HASH.js gzip 581 B 582 B ✓
index-HASH.js gzip 260 B 259 B ✓
link-HASH.js gzip 2.48 kB 2.48 kB ✓
routerDirect..HASH.js gzip 317 B 318 B ✓
script-HASH.js gzip 384 B 386 B ✓
withRouter-HASH.js gzip 316 B 315 B ✓
1afbb74e6ecf..834.css gzip 106 B 106 B ✓
Total 7.95 kB 7.96 kB ⚠️ +4 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 129 kB 129 kB ✓
page.js gzip 294 kB 294 kB ✓
Total 424 kB 423 kB ✅ -808 B
Middleware
Canary PR Change
middleware-b..fest.js gzip 617 B 618 B ✓
middleware-r..fest.js gzip 156 B 156 B ✓
middleware.js gzip 46.2 kB 45.6 kB 🟢 540 B (-1%)
edge-runtime..pack.js gzip 842 B 842 B ✓
Total 47.8 kB 47.2 kB ✅ -539 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 717 B 718 B ✓
Total 717 B 718 B ⚠️ +1 B
Build Cache
Canary PR Change
0.pack gzip 4.83 MB 4.82 MB 🟢 7.25 kB (0%)
index.pack gzip 123 kB 123 kB ✓
index.pack.old gzip 124 kB 125 kB ✓
Total 5.07 MB 5.07 MB ✅ -6.29 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 375 kB 375 kB ✓
app-page-exp..prod.js gzip 207 kB 207 kB ✓
app-page-tur...dev.js gzip 375 kB 375 kB ✓
app-page-tur..prod.js gzip 207 kB 207 kB ✓
app-page-tur...dev.js gzip 371 kB 371 kB ✓
app-page-tur..prod.js gzip 204 kB 204 kB ✓
app-page.run...dev.js gzip 371 kB 371 kB ✓
app-page.run..prod.js gzip 205 kB 205 kB ✓
app-route-ex...dev.js gzip 83.3 kB 83.3 kB ✓
app-route-ex..prod.js gzip 56.3 kB 56.3 kB ✓
app-route-tu...dev.js gzip 83.4 kB 83.4 kB ✓
app-route-tu..prod.js gzip 56.3 kB 56.3 kB ✓
app-route-tu...dev.js gzip 82.9 kB 82.9 kB ✓
app-route-tu..prod.js gzip 56.1 kB 56.1 kB ✓
app-route.ru...dev.js gzip 82.9 kB 82.9 kB ✓
app-route.ru..prod.js gzip 56.1 kB 56.1 kB ✓
dev-validati...dev.js gzip 134 kB 134 kB ✓
dev-validati...dev.js gzip 134 kB 134 kB ✓
dev-validati...dev.js gzip 132 kB 132 kB ✓
dev-validati...dev.js gzip 132 kB 132 kB ✓
dist_client_...dev.js gzip 324 B 324 B ✓
dist_client_...dev.js gzip 326 B 326 B ✓
dist_client_...dev.js gzip 318 B 318 B ✓
dist_client_...dev.js gzip 317 B 317 B ✓
pages-api-tu...dev.js gzip 46.5 kB 46.5 kB ✓
pages-api-tu..prod.js gzip 34.7 kB 34.7 kB ✓
pages-api.ru...dev.js gzip 46.5 kB 46.5 kB ✓
pages-api.ru..prod.js gzip 34.6 kB 34.6 kB ✓
pages-turbo....dev.js gzip 55.3 kB 55.3 kB ✓
pages-turbo...prod.js gzip 40.2 kB 40.2 kB ✓
pages.runtim...dev.js gzip 55.3 kB 55.3 kB ✓
pages.runtim..prod.js gzip 40.2 kB 40.2 kB ✓
server.runti..prod.js gzip 66.7 kB 66.7 kB ✓
use-cache-pr...dev.js gzip 72.8 kB 72.8 kB ✓
use-cache-pr...dev.js gzip 72.8 kB 72.8 kB ✓
use-cache-pr...dev.js gzip 71 kB 71 kB ✓
use-cache-pr...dev.js gzip 71 kB 71 kB ✓
Total 4.11 MB 4.11 MB ✅ -3 B
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/826dd19273b6229f2474d8243025634430da62ed/next

Commit: 826dd19

@github-actions

github-actions Bot commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

Failing test suites

Commit: f696914 | About building and testing Next.js

pnpm test-dev-experimental-turbo test/e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts (turbopack) (Experimental) (job)

  • i18n-app-pages-domain-routing > keeps Pages Router domain locale handling (DD)
  • i18n-app-pages-domain-routing > routes a proxy locale rewrite to a dynamic App page (DD)
Expand output

● i18n-app-pages-domain-routing › keeps Pages Router domain locale handling

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  21 |
  22 |     expect(response.status).toBe(200)
> 23 |     expect(load(await response.text())('#pages-locale').text()).toBe('nl-NL')
     |                                                                 ^
  24 |   })
  25 |
  26 |   it('routes a proxy locale rewrite to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:23:65)

● i18n-app-pages-domain-routing › routes a proxy locale rewrite to a dynamic App page

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  28 |
  29 |     expect(response.status).toBe(200)
> 30 |     expect(load(await response.text())('#app-locale').text()).toBe('nl-NL')
     |                                                               ^
  31 |   })
  32 |
  33 |   it('routes an explicit locale pathname to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:30:63)

pnpm test-dev-experimental-turbo test/development/app-dir/lazy-dynamic-imports/lazy-dynamic-imports.test.ts (turbopack) (Experimental) (job)

  • lazy-dynamic-imports > does not parse a dynamic import target before activation (DD)
Expand output

● lazy-dynamic-imports › does not parse a dynamic import target before activation

expect(received).toContain(expected) // indexOf

Matcher error: received value must not be null nor undefined

Received has value: null

  257 |         await browser.elementByCss('#load-parse-error').click()
  258 |         await waitForRedbox(browser)
> 259 |         expect(await getRedboxSource(browser)).toContain(
      |                                                ^
  260 |           'parse-error-proves-target-was-analyzed'
  261 |         )
  262 |       } finally {

  at Object.toContain (development/app-dir/lazy-dynamic-imports/lazy-dynamic-imports.test.ts:259:48)

pnpm test-start-experimental-turbo test/e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts (turbopack) (Experimental) (job)

  • i18n-app-pages-domain-routing > keeps Pages Router domain locale handling (DD)
  • i18n-app-pages-domain-routing > routes a proxy locale rewrite to a dynamic App page (DD)
Expand output

● i18n-app-pages-domain-routing › keeps Pages Router domain locale handling

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  21 |
  22 |     expect(response.status).toBe(200)
> 23 |     expect(load(await response.text())('#pages-locale').text()).toBe('nl-NL')
     |                                                                 ^
  24 |   })
  25 |
  26 |   it('routes a proxy locale rewrite to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:23:65)

● i18n-app-pages-domain-routing › routes a proxy locale rewrite to a dynamic App page

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  28 |
  29 |     expect(response.status).toBe(200)
> 30 |     expect(load(await response.text())('#app-locale').text()).toBe('nl-NL')
     |                                                               ^
  31 |   })
  32 |
  33 |   it('routes an explicit locale pathname to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:30:63)

pnpm test-dev test/e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts (job)

  • i18n-app-pages-domain-routing > keeps Pages Router domain locale handling (DD)
  • i18n-app-pages-domain-routing > routes a proxy locale rewrite to a dynamic App page (DD)
Expand output

● i18n-app-pages-domain-routing › keeps Pages Router domain locale handling

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  21 |
  22 |     expect(response.status).toBe(200)
> 23 |     expect(load(await response.text())('#pages-locale').text()).toBe('nl-NL')
     |                                                                 ^
  24 |   })
  25 |
  26 |   it('routes a proxy locale rewrite to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:23:65)

● i18n-app-pages-domain-routing › routes a proxy locale rewrite to a dynamic App page

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  28 |
  29 |     expect(response.status).toBe(200)
> 30 |     expect(load(await response.text())('#app-locale').text()).toBe('nl-NL')
     |                                                               ^
  31 |   })
  32 |
  33 |   it('routes an explicit locale pathname to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:30:63)

pnpm test-start test/e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts (job)

  • i18n-app-pages-domain-routing > keeps Pages Router domain locale handling (DD)
  • i18n-app-pages-domain-routing > routes a proxy locale rewrite to a dynamic App page (DD)
Expand output

● i18n-app-pages-domain-routing › keeps Pages Router domain locale handling

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  21 |
  22 |     expect(response.status).toBe(200)
> 23 |     expect(load(await response.text())('#pages-locale').text()).toBe('nl-NL')
     |                                                                 ^
  24 |   })
  25 |
  26 |   it('routes a proxy locale rewrite to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:23:65)

● i18n-app-pages-domain-routing › routes a proxy locale rewrite to a dynamic App page

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  28 |
  29 |     expect(response.status).toBe(200)
> 30 |     expect(load(await response.text())('#app-locale').text()).toBe('nl-NL')
     |                                                               ^
  31 |   })
  32 |
  33 |   it('routes an explicit locale pathname to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:30:63)

pnpm test-dev-turbo test/e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts (turbopack) (job)

  • i18n-app-pages-domain-routing > keeps Pages Router domain locale handling (DD)
  • i18n-app-pages-domain-routing > routes a proxy locale rewrite to a dynamic App page (DD)
Expand output

● i18n-app-pages-domain-routing › keeps Pages Router domain locale handling

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  21 |
  22 |     expect(response.status).toBe(200)
> 23 |     expect(load(await response.text())('#pages-locale').text()).toBe('nl-NL')
     |                                                                 ^
  24 |   })
  25 |
  26 |   it('routes a proxy locale rewrite to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:23:65)

● i18n-app-pages-domain-routing › routes a proxy locale rewrite to a dynamic App page

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  28 |
  29 |     expect(response.status).toBe(200)
> 30 |     expect(load(await response.text())('#app-locale').text()).toBe('nl-NL')
     |                                                               ^
  31 |   })
  32 |
  33 |   it('routes an explicit locale pathname to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:30:63)

pnpm test-start-turbo test/e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts (turbopack) (job)

  • i18n-app-pages-domain-routing > keeps Pages Router domain locale handling (DD)
  • i18n-app-pages-domain-routing > routes a proxy locale rewrite to a dynamic App page (DD)
Expand output

● i18n-app-pages-domain-routing › keeps Pages Router domain locale handling

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  21 |
  22 |     expect(response.status).toBe(200)
> 23 |     expect(load(await response.text())('#pages-locale').text()).toBe('nl-NL')
     |                                                                 ^
  24 |   })
  25 |
  26 |   it('routes a proxy locale rewrite to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:23:65)

● i18n-app-pages-domain-routing › routes a proxy locale rewrite to a dynamic App page

expect(received).toBe(expected) // Object.is equality

Expected: "nl-NL"
Received: "en-US"

  28 |
  29 |     expect(response.status).toBe(200)
> 30 |     expect(load(await response.text())('#app-locale').text()).toBe('nl-NL')
     |                                                               ^
  31 |   })
  32 |
  33 |   it('routes an explicit locale pathname to a dynamic App page', async () => {

  at Object.toBe (e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts:30:63)

@timneutkens
timneutkens force-pushed the codex/versioned-i18n-pages-api-routing branch from 5fb0bda to 07478e8 Compare August 18, 2026 11:17
@timneutkens
timneutkens force-pushed the codex/versioned-i18n-pages-api-routing branch from 07478e8 to 826dd19 Compare August 21, 2026 12:34
@timneutkens
timneutkens force-pushed the codex/versioned-i18n-pages-api-routing branch from 826dd19 to fa9c071 Compare August 31, 2026 08:30
@timneutkens
timneutkens changed the base branch from canary to codex/fix-app-i18n-runtime-routing August 31, 2026 08:30
@timneutkens
timneutkens force-pushed the codex/versioned-i18n-pages-api-routing branch from fa9c071 to c87031a Compare August 31, 2026 09:38
Base automatically changed from codex/fix-app-i18n-runtime-routing to canary September 16, 2026 08:40
timneutkens added a commit that referenced this pull request Sep 16, 2026
## Summary

Fix hybrid App Router and Pages Router projects using Pages i18n so
explicit or rewritten locale segments remain available to App Router
route matching, while Pages routes continue using locale-normalized
paths.

The built-in filesystem matcher now carries each route owner through
`RouteKind`, avoids duplicate App routes being treated as Pages routes
in production, and preserves literal App path parameters through the
router server, direct route-module invocation, and static export paths.
The same ownership information is maintained by the development bundler.

Adds regression coverage for domain locales, proxy rewrites, exact and
dynamic App pages, catch-all parameters, route handlers, inferred
default locales, and Pages routes. Adapter-generated routing metadata is
intentionally handled in the follow-up layers #97366 and #97500.

Closes #86048

## Verification

- `pnpm build-all`
- `NEXT_TEST_PREFER_OFFLINE=1 pnpm test-start-webpack
test/e2e/app-dir/i18n-app-pages-domain-routing/i18n-app-pages-domain-routing.test.ts`
(9 passed)
- Prettier and ESLint checks on all changed files

<!-- NEXT_JS_LLM -->
@timneutkens
timneutkens force-pushed the codex/versioned-i18n-pages-api-routing branch from c87031a to f696914 Compare September 16, 2026 08:40

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