Skip to content

Conversation

@eps1lon
Copy link
Member

@eps1lon eps1lon commented Dec 18, 2025

.next should be excluded if everything else in the root is included. Even if it's just **/*.ts, we still risk including more than necessary.

This fixes issues where cache profiles where not included or routes not validated if .next was excluded to squeeze out every bit of TypeScript performance.

Going forward, new Next.js type-checking should be added to next-env.d.ts. That file is fully controlled by Next.js and churning it, does not churn users since it's not in version control.

We can check how we can best move next-env.d.ts out of the top level folder. But this must be done in a way that's compatible with adding .next into exclude. Telling people to only add certain files to exclude is just another way to churn users when we need to add new folders (if we remember to).

Closes https://linear.app/vercel/issue/NXT-124/

@nextjs-bot nextjs-bot added create-next-app Related to our CLI tool for quickly starting a new Next.js application. created-by: Next.js team PRs by the Next.js team. Documentation Related to Next.js' official documentation. tests type: next labels Dec 18, 2025
@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Dec 18, 2025

Failing test suites

Commit: 4d03cbb | About building and testing Next.js

pnpm test test/integration/app-types/app-types.test.ts (job)

  • app type checking - production mode > should type check invalid entry exports (DD)
Expand output

● app type checking - production mode › should type check invalid entry exports

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

Expected substring: "\"foo\" is not a valid Page export field."
Received string:    "·
[Test Mode] ../../../packages/next
Type error: Layout \"../../../packages/next\" does not match the required types of a Next.js Layout.
  Invalid configuration \"generateStaticParams\":
    Expected \"(props: { params: {}; }) => any[] | Promise<any[]>\", got \"(s: string) => Promise<number>\".
        Expected \"string\", got \"{ params: {}; }\".··
[Test Mode] ../../../packages/next
Type error: Layout \"../../../packages/next\" does not match the required types of a Next.js Layout.
  Invalid configuration \"GET\":
    Expected \"(request: NextRequest, context: { params: Promise<{}>; }) => void | Response | Promise<void | Response>\", got \"(request: boolean) => void\".
        Expected \"boolean\", got \"NextRequest\".··
[Test Mode] ./src/app/type-checks/form/page.tsx:8:13
Type error: Type '\"/wrong-link\"' is not assignable to type '((formData: FormData) => void) | RouteImpl<\"/wrong-link\">'.·
   6 |   const invalidRoutes = (
   7 |     <>
>  8 |       <Form action=\"/wrong-link\"></Form>
     |             ^
   9 |       <Form action=\"/blog/a?1/b\"></Form>
  10 |       <Form action={`/blog/${'a/b/c'}`}></Form>
  11 |     </>·
[Test Mode] ./src/app/type-checks/form/page.tsx:9:13
Type error: Type '\"/blog/a?1/b\"' is not assignable to type '((formData: FormData) => void) | RouteImpl<\"/blog/a?1/b\">'.·
   7 |     <>
   8 |       <Form action=\"/wrong-link\"></Form>
>  9 |       <Form action=\"/blog/a?1/b\"></Form>
     |             ^
  10 |       <Form action={`/blog/${'a/b/c'}`}></Form>
  11 |     </>
  12 |   )·
[Test Mode] ./src/app/type-checks/form/page.tsx:10:13
Type error: Type '\"/blog/a/b/c\"' is not assignable to type '((formData: FormData) => void) | RouteImpl<\"/blog/a/b/c\">'.·
   8 |       <Form action=\"/wrong-link\"></Form>
   9 |       <Form action=\"/blog/a?1/b\"></Form>
> 10 |       <Form action={`/blog/${'a/b/c'}`}></Form>
     |             ^
  11 |     </>
  12 |   )
  13 |·
[Test Mode] ./src/app/type-checks/link/page.tsx:18:13
Type error: Type '\"/(newroot)/dashboard/another\"' is not assignable to type 'URL | Route<\"/(newroot)/dashboard/another\">'.·
  16 |   const shouldFail = (
  17 |     <>
> 18 |       <Card href=\"/(newroot)/dashboard/another\" />
     |             ^
  19 |       <Card href=\"/dashboard\" />
  20 |       <Card href=\"/blog/a/b/c/d\" />
  21 |       <Link href=\"/typing\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:19:13
Type error: Type '\"/dashboard\"' is not assignable to type 'URL | Route<\"/dashboard\">'.·
  17 |     <>
  18 |       <Card href=\"/(newroot)/dashboard/another\" />
> 19 |       <Card href=\"/dashboard\" />
     |             ^
  20 |       <Card href=\"/blog/a/b/c/d\" />
  21 |       <Link href=\"/typing\">test</Link>
  22 |       <Link href=\"/button\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:20:13
Type error: Type '\"/blog/a/b/c/d\"' is not assignable to type 'URL | Route<\"/blog/a/b/c/d\">'.·
  18 |       <Card href=\"/(newroot)/dashboard/another\" />
  19 |       <Card href=\"/dashboard\" />
> 20 |       <Card href=\"/blog/a/b/c/d\" />
     |             ^
  21 |       <Link href=\"/typing\">test</Link>
  22 |       <Link href=\"/button\">test</Link>
  23 |       <Link href=\"/buttooon\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:21:13
Type error: \"/typing\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  19 |       <Card href=\"/dashboard\" />
  20 |       <Card href=\"/blog/a/b/c/d\" />
> 21 |       <Link href=\"/typing\">test</Link>
     |             ^
  22 |       <Link href=\"/button\">test</Link>
  23 |       <Link href=\"/buttooon\">test</Link>
  24 |       <Link href=\"/blog/\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:22:13
Type error: \"/button\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  20 |       <Card href=\"/blog/a/b/c/d\" />
  21 |       <Link href=\"/typing\">test</Link>
> 22 |       <Link href=\"/button\">test</Link>
     |             ^
  23 |       <Link href=\"/buttooon\">test</Link>
  24 |       <Link href=\"/blog/\">test</Link>
  25 |       <Link href=\"/blog/a?1/b\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:23:13
Type error: \"/buttooon\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  21 |       <Link href=\"/typing\">test</Link>
  22 |       <Link href=\"/button\">test</Link>
> 23 |       <Link href=\"/buttooon\">test</Link>
     |             ^
  24 |       <Link href=\"/blog/\">test</Link>
  25 |       <Link href=\"/blog/a?1/b\">test</Link>
  26 |       <Link href=\"/blog/a#1/b\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:24:13
Type error: \"/blog/\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  22 |       <Link href=\"/button\">test</Link>
  23 |       <Link href=\"/buttooon\">test</Link>
> 24 |       <Link href=\"/blog/\">test</Link>
     |             ^
  25 |       <Link href=\"/blog/a?1/b\">test</Link>
  26 |       <Link href=\"/blog/a#1/b\">test</Link>
  27 |       <Link href=\"/blog/v/w/z\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:25:13
Type error: \"/blog/a?1/b\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  23 |       <Link href=\"/buttooon\">test</Link>
  24 |       <Link href=\"/blog/\">test</Link>
> 25 |       <Link href=\"/blog/a?1/b\">test</Link>
     |             ^
  26 |       <Link href=\"/blog/a#1/b\">test</Link>
  27 |       <Link href=\"/blog/v/w/z\">test</Link>
  28 |       <Link href=\"/(newroot)/dashboard/another\" />·
[Test Mode] ./src/app/type-checks/link/page.tsx:26:13
Type error: \"/blog/a#1/b\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  24 |       <Link href=\"/blog/\">test</Link>
  25 |       <Link href=\"/blog/a?1/b\">test</Link>
> 26 |       <Link href=\"/blog/a#1/b\">test</Link>
     |             ^
  27 |       <Link href=\"/blog/v/w/z\">test</Link>
  28 |       <Link href=\"/(newroot)/dashboard/another\" />
  29 |       <Link href=\"/dashboard\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:27:13
Type error: \"/blog/v/w/z\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  25 |       <Link href=\"/blog/a?1/b\">test</Link>
  26 |       <Link href=\"/blog/a#1/b\">test</Link>
> 27 |       <Link href=\"/blog/v/w/z\">test</Link>
     |             ^
  28 |       <Link href=\"/(newroot)/dashboard/another\" />
  29 |       <Link href=\"/dashboard\">test</Link>
  30 |       <Link href={`/blog/a/${test}`}>test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:28:13
Type error: \"/(newroot)/dashboard/another\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  26 |       <Link href=\"/blog/a#1/b\">test</Link>
  27 |       <Link href=\"/blog/v/w/z\">test</Link>
> 28 |       <Link href=\"/(newroot)/dashboard/another\" />
     |             ^
  29 |       <Link href=\"/dashboard\">test</Link>
  30 |       <Link href={`/blog/a/${test}`}>test</Link>
  31 |       <Link href=\"/rewrite-any\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:29:13
Type error: \"/dashboard\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  27 |       <Link href=\"/blog/v/w/z\">test</Link>
  28 |       <Link href=\"/(newroot)/dashboard/another\" />
> 29 |       <Link href=\"/dashboard\">test</Link>
     |             ^
  30 |       <Link href={`/blog/a/${test}`}>test</Link>
  31 |       <Link href=\"/rewrite-any\">test</Link>
  32 |       <Link href=\"/rewrite-one-or-more\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:30:13
Type error: \"/blog/a/a/b\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  28 |       <Link href=\"/(newroot)/dashboard/another\" />
  29 |       <Link href=\"/dashboard\">test</Link>
> 30 |       <Link href={`/blog/a/${test}`}>test</Link>
     |             ^
  31 |       <Link href=\"/rewrite-any\">test</Link>
  32 |       <Link href=\"/rewrite-one-or-more\">test</Link>
  33 |       <Link href=\"/rewrite-param/page\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:31:13
Type error: \"/rewrite-any\" is not an existing route. Did you mean \"/rewrite\" instead? If it is intentional, please type it explicitly with `as Route`.·
  29 |       <Link href=\"/dashboard\">test</Link>
  30 |       <Link href={`/blog/a/${test}`}>test</Link>
> 31 |       <Link href=\"/rewrite-any\">test</Link>
     |             ^
  32 |       <Link href=\"/rewrite-one-or-more\">test</Link>
  33 |       <Link href=\"/rewrite-param/page\">test</Link>
  34 |       <Link href=\"/rewrite-param/x/page1\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:32:13
Type error: \"/rewrite-one-or-more\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  30 |       <Link href={`/blog/a/${test}`}>test</Link>
  31 |       <Link href=\"/rewrite-any\">test</Link>
> 32 |       <Link href=\"/rewrite-one-or-more\">test</Link>
     |             ^
  33 |       <Link href=\"/rewrite-param/page\">test</Link>
  34 |       <Link href=\"/rewrite-param/x/page1\">test</Link>
  35 |       <Link href=\"/redirect/v2/guides/x/page\">test</Link>·
[Test Mode] ./src/app/type-checks/link/page.tsx:33:13
Type error: \"/rewrite-param/page\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  31 |       <Link href=\"/rewrite-any\">test</Link>
  32 |       <Link href=\"/rewrite-one-or-more\">test</Link>
> 33 |       <Link href=\"/rewrite-param/page\">test</Link>
     |             ^
  34 |       <Link href=\"/rewrite-param/x/page1\">test</Link>
  35 |       <Link href=\"/redirect/v2/guides/x/page\">test</Link>
  36 |     </>·
[Test Mode] ./src/app/type-checks/link/page.tsx:34:13
Type error: \"/rewrite-param/x/page1\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  32 |       <Link href=\"/rewrite-one-or-more\">test</Link>
  33 |       <Link href=\"/rewrite-param/page\">test</Link>
> 34 |       <Link href=\"/rewrite-param/x/page1\">test</Link>
     |             ^
  35 |       <Link href=\"/redirect/v2/guides/x/page\">test</Link>
  36 |     </>
  37 |   )·
[Test Mode] ./src/app/type-checks/link/page.tsx:35:13
Type error: \"/redirect/v2/guides/x/page\" is not an existing route. If it is intentional, please type it explicitly with `as Route`.·
  33 |       <Link href=\"/rewrite-param/page\">test</Link>
  34 |       <Link href=\"/rewrite-param/x/page1\">test</Link>
> 35 |       <Link href=\"/redirect/v2/guides/x/page\">test</Link>
     |             ^
  36 |     </>
  37 |   )
  38 |·
[Test Mode] ./src/app/type-checks/redirect/page.tsx:7:14
Type error: Argument of type '\"/wrong-link\"' is not assignable to parameter of type 'RouteImpl<\"/wrong-link\">'.·
   5 |   function testRedirect() {
   6 |     // Invalid routes - these should cause type errors:
>  7 |     redirect('/wrong-link')
     |              ^
   8 |     redirect('/blog/a?1/b')
   9 |     redirect(`/blog/${'a/b/c'}`)
  10 |     permanentRedirect('/nonexistent-route')·
[Test Mode] ./src/app/type-checks/redirect/page.tsx:8:14
Type error: Argument of type '\"/blog/a?1/b\"' is not assignable to parameter of type 'RouteImpl<\"/blog/a?1/b\">'.·
   6 |     // Invalid routes - these should cause type errors:
   7 |     redirect('/wrong-link')
>  8 |     redirect('/blog/a?1/b')
     |              ^
   9 |     redirect(`/blog/${'a/b/c'}`)
  10 |     permanentRedirect('/nonexistent-route')
  11 |     permanentRedirect('/wrong/route')·
[Test Mode] ./src/app/type-checks/redirect/page.tsx:9:14
Type error: Argument of type '\"/blog/a/b/c\"' is not assignable to parameter of type 'RouteImpl<\"/blog/a/b/c\">'.·
   7 |     redirect('/wrong-link')
   8 |     redirect('/blog/a?1/b')
>  9 |     redirect(`/blog/${'a/b/c'}`)
     |              ^
  10 |     permanentRedirect('/nonexistent-route')
  11 |     permanentRedirect('/wrong/route')
  12 |·
[Test Mode] ./src/app/type-checks/redirect/page.tsx:10:23
Type error: Argument of type '\"/nonexistent-route\"' is not assignable to parameter of type 'RouteImpl<\"/nonexistent-route\">'.·
   8 |     redirect('/blog/a?1/b')
   9 |     redirect(`/blog/${'a/b/c'}`)
> 10 |     permanentRedirect('/nonexistent-route')
     |                       ^
  11 |     permanentRedirect('/wrong/route')
  12 |
  13 |     // Correctly typed - these should pass:·
[Test Mode] ./src/app/type-checks/redirect/page.tsx:11:23
Type error: Argument of type '\"/wrong/route\"' is not assignable to parameter of type 'RouteImpl<\"/wrong/route\">'.·
   9 |     redirect(`/blog/${'a/b/c'}`)
  10 |     permanentRedirect('/nonexistent-route')
> 11 |     permanentRedirect('/wrong/route')
     |                       ^
  12 |
  13 |     // Correctly typed - these should pass:
  14 |     redirect('/dashboard/another')·
[Test Mode] ./src/app/type-checks/router/page.tsx:11:17
Type error: Argument of type '\"/wrong-link\"' is not assignable to parameter of type 'RouteImpl<\"/wrong-link\">'.·
   9 |   function test() {
  10 |     // Invalid routes:
> 11 |     router.push('/wrong-link')
     |                 ^
  12 |     router.push('/blog/a?1/b')
  13 |     router.push(`/blog/${'a/b/c'}`)
  14 |·
[Test Mode] ./src/app/type-checks/router/page.tsx:12:17
Type error: Argument of type '\"/blog/a?1/b\"' is not assignable to parameter of type 'RouteImpl<\"/blog/a?1/b\">'.·
  10 |     // Invalid routes:
  11 |     router.push('/wrong-link')
> 12 |     router.push('/blog/a?1/b')
     |                 ^
  13 |     router.push(`/blog/${'a/b/c'}`)
  14 |
  15 |     // Correctly typed:·
[Test Mode] ./src/app/type-checks/router/page.tsx:13:17
Type error: Argument of type '\"/blog/a/b/c\"' is not assignable to parameter of type 'RouteImpl<\"/blog/a/b/c\">'.·
  11 |     router.push('/wrong-link')
  12 |     router.push('/blog/a?1/b')
> 13 |     router.push(`/blog/${'a/b/c'}`)
     |                 ^
  14 |
  15 |     // Correctly typed:
  16 |     router.push('/dashboard/another')·
"

  90 |     it('should type check invalid entry exports', () => {
  91 |       // Can't export arbitrary things.
> 92 |       expect(errors).toContain(`"foo" is not a valid Page export field.`)
     |                      ^
  93 |
  94 |       // Can't export invalid fields.
  95 |       expect(errors).toMatch(

  at Object.toContain (integration/app-types/app-types.test.ts:92:22)

pnpm test-start test/production/app-dir/next-types-plugin/sync-params-type-check/sync-params-type-check.test.ts (job)

  • app-dir - sync-params-type-check > should fail build with sync params (DD)
Expand output

● app-dir - sync-params-type-check › should fail build with sync params

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

Expected: 1
Received: 0

  27 |       )
  28 |       const { exitCode, cliOutput } = await next.build()
> 29 |       expect(exitCode).toBe(1)
     |                        ^
  30 |       expect(cliOutput).toMatch(
  31 |         /Type error: Type '{ params: Params; }' does not satisfy the constraint 'PageProps'/
  32 |       )

  at Object.toBe (production/app-dir/next-types-plugin/sync-params-type-check/sync-params-type-check.test.ts:29:24)

pnpm test-start test/e2e/app-dir/segment-cache/prefetch-runtime/prefetch-runtime.test.ts (job)

  • runtime prefetching > in a private cache > can completely prefetch a page that uses cookies and no uncached IO (DD)
Expand output

● runtime prefetching › in a private cache › can completely prefetch a page that uses cookies and no uncached IO

apiRequestContext.fetch: read ECONNRESET
Call log:
  - → GET http://localhost:44409/in-private-cache/cookies-only?_rsc=180y0
  -   user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/130.0.6723.31 Safari/537.36
  -   accept: */*
  -   accept-encoding: gzip,deflate,br
  -   cookie: testCookie=initialValue
  -   next-test-fetch-priority: low
  -   referer: http://localhost:44409/
  -   next-router-prefetch: 1
  -   next-router-segment-prefetch: /!KGRlZmF1bHQp/in-private-cache
  -   next-url: /
  -   rsc: 1
  -   sec-ch-ua: "Chromium";v="130", "HeadlessChrome";v="130", "Not?A_Brand";v="99"
  -   sec-ch-ua-mobile: ?0
  -   sec-ch-ua-platform: "Linux"

  225 |             // server; we pass the request to the server the immediately.
  226 |             result: (async () => {
> 227 |               const originalResponse = await page.request.fetch(request, {
      |                                                           ^
  228 |                 maxRedirects: 0,
  229 |               })
  230 |

  at fetch (lib/router-act.ts:227:59)
  at lib/router-act.ts:245:13
  at routeHandler (lib/router-act.ts:257:7)

● runtime prefetching › in a private cache › can completely prefetch a page that uses cookies and no uncached IO

apiRequestContext.fetch: read ECONNRESET
Call log:
  - → GET http://localhost:44409/in-private-cache/cookies-only?_rsc=180y0
  -   user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/130.0.6723.31 Safari/537.36
  -   accept: */*
  -   accept-encoding: gzip,deflate,br
  -   cookie: testCookie=initialValue
  -   next-test-fetch-priority: low
  -   referer: http://localhost:44409/
  -   next-router-prefetch: 1
  -   next-router-segment-prefetch: /!KGRlZmF1bHQp/in-private-cache
  -   next-url: /
  -   rsc: 1
  -   sec-ch-ua: "Chromium";v="130", "HeadlessChrome";v="130", "Not?A_Brand";v="99"
  -   sec-ch-ua-mobile: ?0
  -   sec-ch-ua-platform: "Linux"

  225 |             // server; we pass the request to the server the immediately.
  226 |             result: (async () => {
> 227 |               const originalResponse = await page.request.fetch(request, {
      |                                                           ^
  228 |                 maxRedirects: 0,
  229 |               })
  230 |

  at fetch (lib/router-act.ts:227:59)
  at lib/router-act.ts:245:13
  at routeHandler (lib/router-act.ts:257:7)

@nextjs-bot
Copy link
Collaborator

nextjs-bot commented Dec 18, 2025

Stats from current PR

Default Build (Increase detected ⚠️)
General
vercel/next.js canary vercel/next.js sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded Change
buildDuration 17s 14.5s N/A
buildDurationCached 13.8s 10.4s N/A
nodeModulesSize 456 MB 456 MB N/A
nextStartRea..uration (ms) 712ms 721ms N/A
Client Bundles (main, webpack) Overall increase ⚠️
vercel/next.js canary vercel/next.js sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded Change
2086.HASH.js gzip 169 B 169 B
2161-HASH.js gzip 5.39 kB 5.41 kB N/A
2747-HASH.js gzip 4.48 kB 4.46 kB N/A
4322-HASH.js gzip 51.2 kB 50.9 kB N/A
ec793fe8-HASH.js gzip 62.3 kB 62.3 kB N/A
framework-HASH.js gzip 59.8 kB 59.8 kB N/A
main-app-HASH.js gzip 251 B 253 B N/A
main-HASH.js gzip 38.3 kB 38.7 kB ⚠️ +375 B
webpack-HASH.js gzip 1.68 kB 1.69 kB N/A
Overall change 38.5 kB 38.9 kB ⚠️ +375 B
Legacy Client Bundles (polyfills)
vercel/next.js canary vercel/next.js sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Overall change 39.4 kB 39.4 kB
Client Pages
vercel/next.js canary vercel/next.js sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded Change
_app-HASH.js gzip 194 B 193 B N/A
_error-HASH.js gzip 182 B 182 B
css-HASH.js gzip 336 B 335 B N/A
dynamic-HASH.js gzip 1.8 kB 1.8 kB N/A
edge-ssr-HASH.js gzip 256 B 256 B
head-HASH.js gzip 352 B 349 B N/A
hooks-HASH.js gzip 385 B 384 B N/A
image-HASH.js gzip 580 B 580 B
index-HASH.js gzip 259 B 258 B N/A
link-HASH.js gzip 2.5 kB 2.51 kB N/A
routerDirect..HASH.js gzip 319 B 317 B N/A
script-HASH.js gzip 385 B 387 B N/A
withRouter-HASH.js gzip 316 B 315 B N/A
1afbb74e6ecf..834.css gzip 106 B 106 B
Overall change 1.12 kB 1.12 kB
Client Build Manifests
vercel/next.js canary vercel/next.js sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded Change
_buildManifest.js gzip 738 B 738 B
Overall change 738 B 738 B
Rendered Page Sizes
vercel/next.js canary vercel/next.js sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded Change
index.html gzip 524 B 525 B N/A
link.html gzip 539 B 538 B N/A
withRouter.html gzip 521 B 521 B
Overall change 521 B 521 B
Edge SSR bundle Size Overall increase ⚠️
vercel/next.js canary vercel/next.js sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded Change
edge-ssr.js gzip 124 kB 124 kB N/A
page.js gzip 237 kB 238 kB ⚠️ +584 B
Overall change 237 kB 238 kB ⚠️ +584 B
Middleware size Overall increase ⚠️
vercel/next.js canary vercel/next.js sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded Change
middleware-b..fest.js gzip 652 B 654 B N/A
middleware-r..fest.js gzip 155 B 156 B N/A
middleware.js gzip 32.8 kB 32.9 kB ⚠️ +120 B
edge-runtime..pack.js gzip 846 B 846 B
Overall change 33.6 kB 33.7 kB ⚠️ +120 B
Next Runtimes
vercel/next.js canary vercel/next.js sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded Change
app-page-exp...dev.js gzip 301 kB 301 kB N/A
app-page-exp..prod.js gzip 156 kB 156 kB
app-page-tur...dev.js gzip 301 kB 301 kB N/A
app-page-tur..prod.js gzip 156 kB 156 kB
app-page-tur...dev.js gzip 298 kB 298 kB N/A
app-page-tur..prod.js gzip 154 kB 154 kB
app-page.run...dev.js gzip 298 kB 298 kB N/A
app-page.run..prod.js gzip 154 kB 154 kB
app-route-ex...dev.js gzip 68.6 kB 68.6 kB
app-route-ex..prod.js gzip 47.4 kB 47.4 kB
app-route-tu...dev.js gzip 68.6 kB 68.6 kB
app-route-tu..prod.js gzip 47.5 kB 47.5 kB
app-route-tu...dev.js gzip 68.2 kB 68.2 kB
app-route-tu..prod.js gzip 47.2 kB 47.2 kB
app-route.ru...dev.js gzip 68.2 kB 68.2 kB
app-route.ru..prod.js gzip 47.2 kB 47.2 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 41 kB 41 kB
pages-api-tu..prod.js gzip 31.1 kB 31.1 kB
pages-api.ru...dev.js gzip 41 kB 41 kB
pages-api.ru..prod.js gzip 31.1 kB 31.1 kB
pages-turbo....dev.js gzip 50.6 kB 50.6 kB
pages-turbo...prod.js gzip 38.1 kB 38.1 kB
pages.runtim...dev.js gzip 50.6 kB 50.6 kB
pages.runtim..prod.js gzip 38.1 kB 38.1 kB
server.runti..prod.js gzip 59.8 kB 59.8 kB
Overall change 1.47 MB 1.47 MB
build cache Overall increase ⚠️
vercel/next.js canary vercel/next.js sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded Change
0.pack gzip 3.6 MB 3.61 MB ⚠️ +4.34 kB
index.pack gzip 99.3 kB 98.1 kB N/A
Overall change 3.6 MB 3.61 MB ⚠️ +4.34 kB
Diff details
Diff for page.js

Diff too large to display

Diff for middleware.js

Diff too large to display

Diff for edge-ssr.js

Diff too large to display

Diff for _buildManifest.js
@@ -611,35 +611,35 @@ self.__BUILD_MANIFEST = (function (a, b, c) {
       numHashes: NaN,
       bitArray: [],
     },
-    "/": ["static\u002Fchunks\u002Fpages\u002Findex-dda7d8b64d4ba15c.js"],
+    "/": ["static\u002Fchunks\u002Fpages\u002Findex-d95f7ec6af4d2644.js"],
     "/_error": [
-      "static\u002Fchunks\u002Fpages\u002F_error-6ef44d3954f25711.js",
+      "static\u002Fchunks\u002Fpages\u002F_error-209c0c82205a7c9f.js",
     ],
     "/css": [
       "static\u002Fcss\u002Fded6b86ab9cc0a1f.css",
-      "static\u002Fchunks\u002Fpages\u002Fcss-c8aaa7211416a045.js",
+      "static\u002Fchunks\u002Fpages\u002Fcss-62710339bc830ded.js",
     ],
     "/dynamic": [
-      "static\u002Fchunks\u002Fpages\u002Fdynamic-d53bb7f318f342c2.js",
+      "static\u002Fchunks\u002Fpages\u002Fdynamic-8ed3486bb68dd6c6.js",
     ],
     "/edge-ssr": [
-      "static\u002Fchunks\u002Fpages\u002Fedge-ssr-1383106d4a3e7d72.js",
+      "static\u002Fchunks\u002Fpages\u002Fedge-ssr-0db9f7bb610d3072.js",
     ],
-    "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-1db1c4be1a45662f.js"],
-    "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-e6deee5b72a5b112.js"],
+    "/head": ["static\u002Fchunks\u002Fpages\u002Fhead-747416c4075e42aa.js"],
+    "/hooks": ["static\u002Fchunks\u002Fpages\u002Fhooks-8b10205be7505244.js"],
     "/image": [
-      "static\u002Fchunks\u002F2747-90c828280005c0c3.js",
-      "static\u002Fchunks\u002Fpages\u002Fimage-868472cd5e84efc9.js",
+      "static\u002Fchunks\u002F6349-ee9aecde860d4832.js",
+      "static\u002Fchunks\u002Fpages\u002Fimage-f90ae17c3ad1d38b.js",
     ],
-    "/link": ["static\u002Fchunks\u002Fpages\u002Flink-0ec374e48b2ce5d9.js"],
+    "/link": ["static\u002Fchunks\u002Fpages\u002Flink-6ab9a67b348df1bf.js"],
     "/routerDirect": [
-      "static\u002Fchunks\u002Fpages\u002FrouterDirect-1a34bfadbc088491.js",
+      "static\u002Fchunks\u002Fpages\u002FrouterDirect-f132fb471e65a8b9.js",
     ],
     "/script": [
-      "static\u002Fchunks\u002Fpages\u002Fscript-52320f59afbd096d.js",
+      "static\u002Fchunks\u002Fpages\u002Fscript-8e2028e44b8da2d9.js",
     ],
     "/withRouter": [
-      "static\u002Fchunks\u002Fpages\u002FwithRouter-3b1a16d3dfa21c16.js",
+      "static\u002Fchunks\u002Fpages\u002FwithRouter-a86d259faa012c1c.js",
     ],
     sortedPages: [
       "\u002F",
Diff for dynamic-HASH.js
@@ -1,17 +1,24 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [2291],
   {
-    /***/ 1231: /***/ (
-      module,
+    /***/ 2604: /***/ (
+      __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(4464);
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/dynamic",
+        function () {
+          return __webpack_require__(3643);
+        },
+      ]);
+      if (false) {
+      }
 
       /***/
     },
 
-    /***/ 2101: /***/ (
+    /***/ 3401: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -38,24 +45,63 @@
       /***/
     },
 
-    /***/ 3458: /***/ (
+    /***/ 3643: /***/ (
       __unused_webpack_module,
-      __unused_webpack_exports,
+      __webpack_exports__,
       __webpack_require__
     ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/dynamic",
-        function () {
-          return __webpack_require__(9381);
-        },
-      ]);
-      if (false) {
-      }
+      "use strict";
+      __webpack_require__.r(__webpack_exports__);
+      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
+        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
+        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
+        /* harmony export */
+      });
+      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
+        __webpack_require__(3108);
+      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1__ =
+        __webpack_require__(3973);
+      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1___default =
+        /*#__PURE__*/ __webpack_require__.n(
+          next_dynamic__WEBPACK_IMPORTED_MODULE_1__
+        );
+
+      const DynamicHello = next_dynamic__WEBPACK_IMPORTED_MODULE_1___default()(
+        () =>
+          __webpack_require__
+            .e(/* import() */ 1596)
+            .then(__webpack_require__.bind(__webpack_require__, 1596))
+            .then((mod) => mod.Hello),
+        {
+          loadableGenerated: {
+            webpack: () => [/*require.resolve*/ 1596],
+          },
+        }
+      );
+      const Page = () =>
+        /*#__PURE__*/ (0, react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(
+          react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,
+          {
+            children: [
+              /*#__PURE__*/ (0,
+              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
+                children: "testing next/dynamic size",
+              }),
+              /*#__PURE__*/ (0,
+              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
+                DynamicHello,
+                {}
+              ),
+            ],
+          }
+        );
+      var __N_SSP = true;
+      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = Page;
 
       /***/
     },
 
-    /***/ 4464: /***/ (module, exports, __webpack_require__) => {
+    /***/ 3660: /***/ (module, exports, __webpack_require__) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -88,7 +134,7 @@
         __webpack_require__(4312)
       );
       const _loadablesharedruntime = /*#__PURE__*/ _interop_require_default._(
-        __webpack_require__(9799)
+        __webpack_require__(4539)
       );
       const isServerSide = "object" === "undefined";
       // Normalize loader to return the module as form { default: Component } for `React.lazy`.
@@ -188,63 +234,17 @@
       /***/
     },
 
-    /***/ 9381: /***/ (
-      __unused_webpack_module,
-      __webpack_exports__,
+    /***/ 3973: /***/ (
+      module,
+      __unused_webpack_exports,
       __webpack_require__
     ) => {
-      "use strict";
-      __webpack_require__.r(__webpack_exports__);
-      /* harmony export */ __webpack_require__.d(__webpack_exports__, {
-        /* harmony export */ __N_SSP: () => /* binding */ __N_SSP,
-        /* harmony export */ default: () => __WEBPACK_DEFAULT_EXPORT__,
-        /* harmony export */
-      });
-      /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
-        __webpack_require__(3108);
-      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1231);
-      /* harmony import */ var next_dynamic__WEBPACK_IMPORTED_MODULE_1___default =
-        /*#__PURE__*/ __webpack_require__.n(
-          next_dynamic__WEBPACK_IMPORTED_MODULE_1__
-        );
-
-      const DynamicHello = next_dynamic__WEBPACK_IMPORTED_MODULE_1___default()(
-        () =>
-          __webpack_require__
-            .e(/* import() */ 2086)
-            .then(__webpack_require__.bind(__webpack_require__, 2086))
-            .then((mod) => mod.Hello),
-        {
-          loadableGenerated: {
-            webpack: () => [/*require.resolve*/ 2086],
-          },
-        }
-      );
-      const Page = () =>
-        /*#__PURE__*/ (0, react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsxs)(
-          react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.Fragment,
-          {
-            children: [
-              /*#__PURE__*/ (0,
-              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)("p", {
-                children: "testing next/dynamic size",
-              }),
-              /*#__PURE__*/ (0,
-              react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__.jsx)(
-                DynamicHello,
-                {}
-              ),
-            ],
-          }
-        );
-      var __N_SSP = true;
-      /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = Page;
+      module.exports = __webpack_require__(3660);
 
       /***/
     },
 
-    /***/ 9799: /***/ (
+    /***/ 4539: /***/ (
       __unused_webpack_module,
       exports,
       __webpack_require__
@@ -286,7 +286,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
       const _react = /*#__PURE__*/ _interop_require_default._(
         __webpack_require__(4312)
       );
-      const _loadablecontextsharedruntime = __webpack_require__(2101);
+      const _loadablecontextsharedruntime = __webpack_require__(3401);
       function resolve(obj) {
         return obj && obj.default ? obj.default : obj;
       }
@@ -524,7 +524,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(3458)
+      __webpack_exec__(2604)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for edge-ssr-HASH.js
@@ -1,7 +1,24 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [676],
   {
-    /***/ 1564: /***/ (
+    /***/ 7046: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/edge-ssr",
+        function () {
+          return __webpack_require__(7142);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 7142: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -20,30 +37,13 @@
 
       /***/
     },
-
-    /***/ 4300: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/edge-ssr",
-        function () {
-          return __webpack_require__(1564);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(4300)
+      __webpack_exec__(7046)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for head-HASH.js
@@ -1,34 +1,17 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [5350],
   {
-    /***/ 1548: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/head",
-        function () {
-          return __webpack_require__(4282);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 3952: /***/ (
+    /***/ 3770: /***/ (
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(1653);
+      module.exports = __webpack_require__(9025);
 
       /***/
     },
 
-    /***/ 4282: /***/ (
+    /***/ 6236: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -43,7 +26,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_head__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(3952);
+        __webpack_require__(3770);
       /* harmony import */ var next_head__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_head__WEBPACK_IMPORTED_MODULE_1__
@@ -76,13 +59,30 @@
 
       /***/
     },
+
+    /***/ 6510: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/head",
+        function () {
+          return __webpack_require__(6236);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(1548)
+      __webpack_exec__(6510)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for index-HASH.js
@@ -1,24 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [3332],
   {
-    /***/ 6376: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/",
-        function () {
-          return __webpack_require__(8460);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 8460: /***/ (
+    /***/ 830: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -36,13 +19,30 @@
 
       /***/
     },
+
+    /***/ 1938: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/",
+        function () {
+          return __webpack_require__(830);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(6376)
+      __webpack_exec__(1938)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for link-HASH.js
@@ -1,7 +1,220 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [4672],
   {
-    /***/ 857: /***/ (module, exports, __webpack_require__) => {
+    /***/ 2774: /***/ (module, exports, __webpack_require__) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "useIntersection", {
+        enumerable: true,
+        get: function () {
+          return useIntersection;
+        },
+      });
+      const _react = __webpack_require__(4312);
+      const _requestidlecallback = __webpack_require__(9413);
+      const hasIntersectionObserver =
+        typeof IntersectionObserver === "function";
+      const observers = new Map();
+      const idList = [];
+      function createObserver(options) {
+        const id = {
+          root: options.root || null,
+          margin: options.rootMargin || "",
+        };
+        const existing = idList.find(
+          (obj) => obj.root === id.root && obj.margin === id.margin
+        );
+        let instance;
+        if (existing) {
+          instance = observers.get(existing);
+          if (instance) {
+            return instance;
+          }
+        }
+        const elements = new Map();
+        const observer = new IntersectionObserver((entries) => {
+          entries.forEach((entry) => {
+            const callback = elements.get(entry.target);
+            const isVisible =
+              entry.isIntersecting || entry.intersectionRatio > 0;
+            if (callback && isVisible) {
+              callback(isVisible);
+            }
+          });
+        }, options);
+        instance = {
+          id,
+          observer,
+          elements,
+        };
+        idList.push(id);
+        observers.set(id, instance);
+        return instance;
+      }
+      function observe(element, callback, options) {
+        const { id, observer, elements } = createObserver(options);
+        elements.set(element, callback);
+        observer.observe(element);
+        return function unobserve() {
+          elements.delete(element);
+          observer.unobserve(element);
+          // Destroy observer when there's nothing left to watch:
+          if (elements.size === 0) {
+            observer.disconnect();
+            observers.delete(id);
+            const index = idList.findIndex(
+              (obj) => obj.root === id.root && obj.margin === id.margin
+            );
+            if (index > -1) {
+              idList.splice(index, 1);
+            }
+          }
+        };
+      }
+      function useIntersection({ rootRef, rootMargin, disabled }) {
+        const isDisabled = disabled || !hasIntersectionObserver;
+        const [visible, setVisible] = (0, _react.useState)(false);
+        const elementRef = (0, _react.useRef)(null);
+        const setElement = (0, _react.useCallback)((element) => {
+          elementRef.current = element;
+        }, []);
+        (0, _react.useEffect)(() => {
+          if (hasIntersectionObserver) {
+            if (isDisabled || visible) return;
+            const element = elementRef.current;
+            if (element && element.tagName) {
+              const unobserve = observe(
+                element,
+                (isVisible) => isVisible && setVisible(isVisible),
+                {
+                  root: rootRef?.current,
+                  rootMargin,
+                }
+              );
+              return unobserve;
+            }
+          } else {
+            if (!visible) {
+              const idleCallback = (0,
+              _requestidlecallback.requestIdleCallback)(() => setVisible(true));
+              return () =>
+                (0, _requestidlecallback.cancelIdleCallback)(idleCallback);
+            }
+          }
+          // eslint-disable-next-line react-hooks/exhaustive-deps
+        }, [isDisabled, rootMargin, rootRef, visible, elementRef.current]);
+        const resetVisible = (0, _react.useCallback)(() => {
+          setVisible(false);
+        }, []);
+        return [setElement, visible, resetVisible];
+      }
+      if (
+        (typeof exports.default === "function" ||
+          (typeof exports.default === "object" && exports.default !== null)) &&
+        typeof exports.default.__esModule === "undefined"
+      ) {
+        Object.defineProperty(exports.default, "__esModule", {
+          value: true,
+        });
+        Object.assign(exports.default, exports);
+        module.exports = exports.default;
+      } //# sourceMappingURL=use-intersection.js.map
+
+      /***/
+    },
+
+    /***/ 3351: /***/ (module, exports, __webpack_require__) => {
+      "use strict";
+
+      Object.defineProperty(exports, "__esModule", {
+        value: true,
+      });
+      Object.defineProperty(exports, "useMergedRef", {
+        enumerable: true,
+        get: function () {
+          return useMergedRef;
+        },
+      });
+      const _react = __webpack_require__(4312);
+      function useMergedRef(refA, refB) {
+        const cleanupA = (0, _react.useRef)(null);
+        const cleanupB = (0, _react.useRef)(null);
+        // NOTE: In theory, we could skip the wrapping if only one of the refs is non-null.
+        // (this happens often if the user doesn't pass a ref to Link/Form/Image)
+        // But this can cause us to leak a cleanup-ref into user code (previously via `<Link legacyBehavior>`),
+        // and the user might pass that ref into ref-merging library that doesn't support cleanup refs
+        // (because it hasn't been updated for React 19)
+        // which can then cause things to blow up, because a cleanup-returning ref gets called with `null`.
+        // So in practice, it's safer to be defensive and always wrap the ref, even on React 19.
+        return (0, _react.useCallback)(
+          (current) => {
+            if (current === null) {
+              const cleanupFnA = cleanupA.current;
+              if (cleanupFnA) {
+                cleanupA.current = null;
+                cleanupFnA();
+              }
+              const cleanupFnB = cleanupB.current;
+              if (cleanupFnB) {
+                cleanupB.current = null;
+                cleanupFnB();
+              }
+            } else {
+              if (refA) {
+                cleanupA.current = applyRef(refA, current);
+              }
+              if (refB) {
+                cleanupB.current = applyRef(refB, current);
+              }
+            }
+          },
+          [refA, refB]
+        );
+      }
+      function applyRef(refA, current) {
+        if (typeof refA === "function") {
+          const cleanup = refA(current);
+          if (typeof cleanup === "function") {
+            return cleanup;
+          } else {
+            return () => refA(null);
+          }
+        } else {
+          refA.current = current;
+          return () => {
+            refA.current = null;
+          };
+        }
+      }
+      if (
+        (typeof exports.default === "function" ||
+          (typeof exports.default === "object" && exports.default !== null)) &&
+        typeof exports.default.__esModule === "undefined"
+      ) {
+        Object.defineProperty(exports.default, "__esModule", {
+          value: true,
+        });
+        Object.assign(exports.default, exports);
+        module.exports = exports.default;
+      } //# sourceMappingURL=use-merged-ref.js.map
+
+      /***/
+    },
+
+    /***/ 3440: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(4757);
+
+      /***/
+    },
+
+    /***/ 4757: /***/ (module, exports, __webpack_require__) => {
       "use strict";
       /* __next_internal_client_entry_do_not_use__  cjs */
       Object.defineProperty(exports, "__esModule", {
@@ -23,22 +236,22 @@
           return useLinkStatus;
         },
       });
-      const _interop_require_wildcard = __webpack_require__(8781);
+      const _interop_require_wildcard = __webpack_require__(1162);
       const _jsxruntime = __webpack_require__(3108);
       const _react = /*#__PURE__*/ _interop_require_wildcard._(
         __webpack_require__(4312)
       );
-      const _resolvehref = __webpack_require__(4055);
-      const _islocalurl = __webpack_require__(7175);
-      const _formaturl = __webpack_require__(9674);
-      const _utils = __webpack_require__(7424);
-      const _addlocale = __webpack_require__(589);
-      const _routercontextsharedruntime = __webpack_require__(7010);
-      const _useintersection = __webpack_require__(2330);
-      const _getdomainlocale = __webpack_require__(7207);
-      const _addbasepath = __webpack_require__(9942);
-      const _usemergedref = __webpack_require__(8067);
-      const _erroronce = __webpack_require__(1945);
+      const _resolvehref = __webpack_require__(4691);
+      const _islocalurl = __webpack_require__(4763);
+      const _formaturl = __webpack_require__(3246);
+      const _utils = __webpack_require__(7372);
+      const _addlocale = __webpack_require__(1809);
+      const _routercontextsharedruntime = __webpack_require__(2254);
+      const _useintersection = __webpack_require__(2774);
+      const _getdomainlocale = __webpack_require__(8803);
+      const _addbasepath = __webpack_require__(5834);
+      const _usemergedref = __webpack_require__(3351);
+      const _erroronce = __webpack_require__(6021);
       const prefetched = new Set();
       function prefetch(router, href, as, options) {
         if (false) {
@@ -417,168 +630,43 @@
       /***/
     },
 
-    /***/ 1945: /***/ (__unused_webpack_module, exports) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "errorOnce", {
-        enumerable: true,
-        get: function () {
-          return errorOnce;
+    /***/ 5326: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/link",
+        function () {
+          return __webpack_require__(9058);
         },
-      });
-      let errorOnce = (_) => {};
+      ]);
       if (false) {
-      } //# sourceMappingURL=error-once.js.map
+      }
 
       /***/
     },
 
-    /***/ 2330: /***/ (module, exports, __webpack_require__) => {
+    /***/ 6021: /***/ (__unused_webpack_module, exports) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
         value: true,
       });
-      Object.defineProperty(exports, "useIntersection", {
+      Object.defineProperty(exports, "errorOnce", {
         enumerable: true,
         get: function () {
-          return useIntersection;
+          return errorOnce;
         },
       });
-      const _react = __webpack_require__(4312);
-      const _requestidlecallback = __webpack_require__(601);
-      const hasIntersectionObserver =
-        typeof IntersectionObserver === "function";
-      const observers = new Map();
-      const idList = [];
-      function createObserver(options) {
-        const id = {
-          root: options.root || null,
-          margin: options.rootMargin || "",
-        };
-        const existing = idList.find(
-          (obj) => obj.root === id.root && obj.margin === id.margin
-        );
-        let instance;
-        if (existing) {
-          instance = observers.get(existing);
-          if (instance) {
-            return instance;
-          }
-        }
-        const elements = new Map();
-        const observer = new IntersectionObserver((entries) => {
-          entries.forEach((entry) => {
-            const callback = elements.get(entry.target);
-            const isVisible =
-              entry.isIntersecting || entry.intersectionRatio > 0;
-            if (callback && isVisible) {
-              callback(isVisible);
-            }
-          });
-        }, options);
-        instance = {
-          id,
-          observer,
-          elements,
-        };
-        idList.push(id);
-        observers.set(id, instance);
-        return instance;
-      }
-      function observe(element, callback, options) {
-        const { id, observer, elements } = createObserver(options);
-        elements.set(element, callback);
-        observer.observe(element);
-        return function unobserve() {
-          elements.delete(element);
-          observer.unobserve(element);
-          // Destroy observer when there's nothing left to watch:
-          if (elements.size === 0) {
-            observer.disconnect();
-            observers.delete(id);
-            const index = idList.findIndex(
-              (obj) => obj.root === id.root && obj.margin === id.margin
-            );
-            if (index > -1) {
-              idList.splice(index, 1);
-            }
-          }
-        };
-      }
-      function useIntersection({ rootRef, rootMargin, disabled }) {
-        const isDisabled = disabled || !hasIntersectionObserver;
-        const [visible, setVisible] = (0, _react.useState)(false);
-        const elementRef = (0, _react.useRef)(null);
-        const setElement = (0, _react.useCallback)((element) => {
-          elementRef.current = element;
-        }, []);
-        (0, _react.useEffect)(() => {
-          if (hasIntersectionObserver) {
-            if (isDisabled || visible) return;
-            const element = elementRef.current;
-            if (element && element.tagName) {
-              const unobserve = observe(
-                element,
-                (isVisible) => isVisible && setVisible(isVisible),
-                {
-                  root: rootRef?.current,
-                  rootMargin,
-                }
-              );
-              return unobserve;
-            }
-          } else {
-            if (!visible) {
-              const idleCallback = (0,
-              _requestidlecallback.requestIdleCallback)(() => setVisible(true));
-              return () =>
-                (0, _requestidlecallback.cancelIdleCallback)(idleCallback);
-            }
-          }
-          // eslint-disable-next-line react-hooks/exhaustive-deps
-        }, [isDisabled, rootMargin, rootRef, visible, elementRef.current]);
-        const resetVisible = (0, _react.useCallback)(() => {
-          setVisible(false);
-        }, []);
-        return [setElement, visible, resetVisible];
-      }
-      if (
-        (typeof exports.default === "function" ||
-          (typeof exports.default === "object" && exports.default !== null)) &&
-        typeof exports.default.__esModule === "undefined"
-      ) {
-        Object.defineProperty(exports.default, "__esModule", {
-          value: true,
-        });
-        Object.assign(exports.default, exports);
-        module.exports = exports.default;
-      } //# sourceMappingURL=use-intersection.js.map
-
-      /***/
-    },
-
-    /***/ 4972: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/link",
-        function () {
-          return __webpack_require__(7600);
-        },
-      ]);
+      let errorOnce = (_) => {};
       if (false) {
-      }
+      } //# sourceMappingURL=error-once.js.map
 
       /***/
     },
 
-    /***/ 7207: /***/ (module, exports, __webpack_require__) => {
+    /***/ 8803: /***/ (module, exports, __webpack_require__) => {
       "use strict";
 
       Object.defineProperty(exports, "__esModule", {
@@ -590,7 +678,7 @@
           return getDomainLocale;
         },
       });
-      const _normalizetrailingslash = __webpack_require__(151);
+      const _normalizetrailingslash = __webpack_require__(1315);
       const basePath =
         /* unused pure expression or super */ null && (false || "");
       function getDomainLocale(path, locale, locales, domainLocales) {
@@ -614,7 +702,7 @@
       /***/
     },
 
-    /***/ 7600: /***/ (
+    /***/ 9058: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -629,7 +717,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(7830);
+        __webpack_require__(3440);
       /* harmony import */ var next_link__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_link__WEBPACK_IMPORTED_MODULE_1__
@@ -659,101 +747,13 @@
 
       /***/
     },
-
-    /***/ 7830: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(857);
-
-      /***/
-    },
-
-    /***/ 8067: /***/ (module, exports, __webpack_require__) => {
-      "use strict";
-
-      Object.defineProperty(exports, "__esModule", {
-        value: true,
-      });
-      Object.defineProperty(exports, "useMergedRef", {
-        enumerable: true,
-        get: function () {
-          return useMergedRef;
-        },
-      });
-      const _react = __webpack_require__(4312);
-      function useMergedRef(refA, refB) {
-        const cleanupA = (0, _react.useRef)(null);
-        const cleanupB = (0, _react.useRef)(null);
-        // NOTE: In theory, we could skip the wrapping if only one of the refs is non-null.
-        // (this happens often if the user doesn't pass a ref to Link/Form/Image)
-        // But this can cause us to leak a cleanup-ref into user code (previously via `<Link legacyBehavior>`),
-        // and the user might pass that ref into ref-merging library that doesn't support cleanup refs
-        // (because it hasn't been updated for React 19)
-        // which can then cause things to blow up, because a cleanup-returning ref gets called with `null`.
-        // So in practice, it's safer to be defensive and always wrap the ref, even on React 19.
-        return (0, _react.useCallback)(
-          (current) => {
-            if (current === null) {
-              const cleanupFnA = cleanupA.current;
-              if (cleanupFnA) {
-                cleanupA.current = null;
-                cleanupFnA();
-              }
-              const cleanupFnB = cleanupB.current;
-              if (cleanupFnB) {
-                cleanupB.current = null;
-                cleanupFnB();
-              }
-            } else {
-              if (refA) {
-                cleanupA.current = applyRef(refA, current);
-              }
-              if (refB) {
-                cleanupB.current = applyRef(refB, current);
-              }
-            }
-          },
-          [refA, refB]
-        );
-      }
-      function applyRef(refA, current) {
-        if (typeof refA === "function") {
-          const cleanup = refA(current);
-          if (typeof cleanup === "function") {
-            return cleanup;
-          } else {
-            return () => refA(null);
-          }
-        } else {
-          refA.current = current;
-          return () => {
-            refA.current = null;
-          };
-        }
-      }
-      if (
-        (typeof exports.default === "function" ||
-          (typeof exports.default === "object" && exports.default !== null)) &&
-        typeof exports.default.__esModule === "undefined"
-      ) {
-        Object.defineProperty(exports.default, "__esModule", {
-          value: true,
-        });
-        Object.assign(exports.default, exports);
-        module.exports = exports.default;
-      } //# sourceMappingURL=use-merged-ref.js.map
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(4972)
+      __webpack_exec__(5326)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for routerDirect-HASH.js
@@ -1,17 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [188],
   {
-    /***/ 1179: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(9864);
-
-      /***/
-    },
-
-    /***/ 1640: /***/ (
+    /***/ 2014: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -26,7 +16,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1179);
+        __webpack_require__(4169);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_router__WEBPACK_IMPORTED_MODULE_1__
@@ -46,7 +36,17 @@
       /***/
     },
 
-    /***/ 2172: /***/ (
+    /***/ 4169: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(9700);
+
+      /***/
+    },
+
+    /***/ 4414: /***/ (
       __unused_webpack_module,
       __unused_webpack_exports,
       __webpack_require__
@@ -54,7 +54,7 @@
       (window.__NEXT_P = window.__NEXT_P || []).push([
         "/routerDirect",
         function () {
-          return __webpack_require__(1640);
+          return __webpack_require__(2014);
         },
       ]);
       if (false) {
@@ -68,7 +68,7 @@
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(2172)
+      __webpack_exec__(4414)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for script-HASH.js
@@ -1,17 +1,34 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [1209],
   {
-    /***/ 4977: /***/ (
+    /***/ 2591: /***/ (
       module,
       __unused_webpack_exports,
       __webpack_require__
     ) => {
-      module.exports = __webpack_require__(326);
+      module.exports = __webpack_require__(4634);
 
       /***/
     },
 
-    /***/ 5887: /***/ (
+    /***/ 5030: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/script",
+        function () {
+          return __webpack_require__(7557);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 7557: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -26,7 +43,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_script__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(4977);
+        __webpack_require__(2591);
       /* harmony import */ var next_script__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_script__WEBPACK_IMPORTED_MODULE_1__
@@ -58,30 +75,13 @@
 
       /***/
     },
-
-    /***/ 6268: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/script",
-        function () {
-          return __webpack_require__(5887);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(6268)
+      __webpack_exec__(5030)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for withRouter-HASH.js
@@ -1,34 +1,7 @@
 (self["webpackChunk_N_E"] = self["webpackChunk_N_E"] || []).push([
   [3263],
   {
-    /***/ 1179: /***/ (
-      module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      module.exports = __webpack_require__(9864);
-
-      /***/
-    },
-
-    /***/ 2028: /***/ (
-      __unused_webpack_module,
-      __unused_webpack_exports,
-      __webpack_require__
-    ) => {
-      (window.__NEXT_P = window.__NEXT_P || []).push([
-        "/withRouter",
-        function () {
-          return __webpack_require__(4501);
-        },
-      ]);
-      if (false) {
-      }
-
-      /***/
-    },
-
-    /***/ 4501: /***/ (
+    /***/ 559: /***/ (
       __unused_webpack_module,
       __webpack_exports__,
       __webpack_require__
@@ -43,7 +16,7 @@
       /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_0__ =
         __webpack_require__(3108);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1__ =
-        __webpack_require__(1179);
+        __webpack_require__(4169);
       /* harmony import */ var next_router__WEBPACK_IMPORTED_MODULE_1___default =
         /*#__PURE__*/ __webpack_require__.n(
           next_router__WEBPACK_IMPORTED_MODULE_1__
@@ -61,13 +34,40 @@
 
       /***/
     },
+
+    /***/ 726: /***/ (
+      __unused_webpack_module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      (window.__NEXT_P = window.__NEXT_P || []).push([
+        "/withRouter",
+        function () {
+          return __webpack_require__(559);
+        },
+      ]);
+      if (false) {
+      }
+
+      /***/
+    },
+
+    /***/ 4169: /***/ (
+      module,
+      __unused_webpack_exports,
+      __webpack_require__
+    ) => {
+      module.exports = __webpack_require__(9700);
+
+      /***/
+    },
   },
   /******/ (__webpack_require__) => {
     // webpackRuntimeModules
     /******/ var __webpack_exec__ = (moduleId) =>
       __webpack_require__((__webpack_require__.s = moduleId));
     /******/ __webpack_require__.O(0, [636, 6593, 8792], () =>
-      __webpack_exec__(2028)
+      __webpack_exec__(726)
     );
     /******/ var __webpack_exports__ = __webpack_require__.O();
     /******/ _N_E = __webpack_exports__;
Diff for 2161-HASH.js

Diff too large to display

Diff for 2747-HASH.js

Diff too large to display

Diff for 4322-HASH.js
failed to diff
Diff for main-HASH.js

Diff too large to display

Commit: 4d03cbb

@eps1lon eps1lon force-pushed the sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded branch from ec6cf49 to 6ae7a6b Compare December 18, 2025 21:24
userTsConfig.include = hasAppDir
? ['next-env.d.ts', ...nextAppTypes, '**/*.mts', '**/*.ts', '**/*.tsx']
: ['next-env.d.ts', '**/*.mts', '**/*.ts', '**/*.tsx']
// Use next-env to include more Next.js specific types.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code no longer ensures that next-env.d.ts is included in the TypeScript configuration for projects with existing include arrays. This could cause type-related issues for projects where next-env.d.ts is not explicitly listed in the include configuration.

View Details
📝 Patch Details
diff --git a/packages/next/src/lib/typescript/writeConfigurationDefaults.test.ts b/packages/next/src/lib/typescript/writeConfigurationDefaults.test.ts
index e762f5e80a..33cf6979d0 100644
--- a/packages/next/src/lib/typescript/writeConfigurationDefaults.test.ts
+++ b/packages/next/src/lib/typescript/writeConfigurationDefaults.test.ts
@@ -171,5 +171,67 @@ describe('writeConfigurationDefaults()', () => {
         })
       })
     })
+
+    it('adds next-env.d.ts to existing include array when missing', async () => {
+      const content = {
+        compilerOptions: {},
+        include: ['src/**/*.ts', 'src/**/*.tsx'],
+      }
+
+      await writeFile(tsConfigPath, JSON.stringify(content, null, 2))
+
+      await writeConfigurationDefaults(
+        ts.version,
+        tsConfigPath,
+        isFirstTimeSetup,
+        hasAppDir,
+        hasPagesDir
+      )
+
+      const output = await readFile(tsConfigPath, 'utf-8')
+      const parsed = JSON.parse(output)
+
+      expect(parsed.include).toEqual([
+        'next-env.d.ts',
+        'src/**/*.ts',
+        'src/**/*.tsx',
+      ])
+
+      const logOutput = stripAnsi(consoleLogSpy.mock.calls.flat().join('\n'))
+      expect(logOutput).toContain(
+        'include was updated to add \'next-env.d.ts\''
+      )
+    })
+
+    it('does not duplicate next-env.d.ts in include array', async () => {
+      const content = {
+        compilerOptions: {},
+        include: ['next-env.d.ts', 'src/**/*.ts', 'src/**/*.tsx'],
+      }
+
+      await writeFile(tsConfigPath, JSON.stringify(content, null, 2))
+
+      await writeConfigurationDefaults(
+        ts.version,
+        tsConfigPath,
+        isFirstTimeSetup,
+        hasAppDir,
+        hasPagesDir
+      )
+
+      const output = await readFile(tsConfigPath, 'utf-8')
+      const parsed = JSON.parse(output)
+
+      expect(parsed.include).toEqual([
+        'next-env.d.ts',
+        'src/**/*.ts',
+        'src/**/*.tsx',
+      ])
+
+      const logOutput = stripAnsi(consoleLogSpy.mock.calls.flat().join('\n'))
+      expect(logOutput).not.toContain(
+        'include was updated to add \'next-env.d.ts\''
+      )
+    })
   })
 })
diff --git a/packages/next/src/lib/typescript/writeConfigurationDefaults.ts b/packages/next/src/lib/typescript/writeConfigurationDefaults.ts
index 66218c23af..5df0abc01e 100644
--- a/packages/next/src/lib/typescript/writeConfigurationDefaults.ts
+++ b/packages/next/src/lib/typescript/writeConfigurationDefaults.ts
@@ -274,6 +274,17 @@ export async function writeConfigurationDefaults(
         ' was set to ' +
         bold(`['next-env.d.ts', '**/*.mts', '**/*.ts', '**/*.tsx']`)
     )
+  } else if (
+    Array.isArray(userTsConfig.include) &&
+    !userTsConfig.include.includes('next-env.d.ts')
+  ) {
+    // Ensure next-env.d.ts is included for projects with existing include arrays.
+    // This is necessary for TypeScript to process the type imports from next-env.d.ts,
+    // which include .next/types/**/*.ts files that define route types and other Next.js types.
+    userTsConfig.include.unshift('next-env.d.ts')
+    suggestedActions.push(
+      cyan('include') + ' was updated to add ' + bold(`'next-env.d.ts'`)
+    )
   }
 
   // Enable the Next.js typescript plugin.

Analysis

Missing next-env.d.ts in include array causes type definitions to be unavailable

What fails: Projects with an existing include array in tsconfig.json that doesn't contain next-env.d.ts won't have access to Next.js type definitions (routes, cache-life, validator, link types) because TypeScript won't include the next-env.d.ts file that imports from .next/types/**/*.ts.

How to reproduce:

  1. Create a Next.js project with app directory

  2. Manually edit tsconfig.json to have a custom include array without next-env.d.ts:

    {
      "include": ["src/**/*.ts", "src/**/*.tsx"],
      "compilerOptions": {}
    }
  3. Run next dev which calls verifyTypeScriptSetup()

  4. Open a file and try to use typed routes or other Next.js type definitions

Result: Types from .next/types/**/*.ts (routes.d.ts, cache-life.d.ts, validator.ts, link.d.ts) won't be available in the project

Expected: next-env.d.ts should be automatically added to the include array so TypeScript can follow the imports in that file and process the .next/types/**/*.ts definitions, even though .next is in the exclude array (TypeScript follows imports from included files regardless of exclusions, per TSConfig reference)

Root cause: In commit 6ae7a6b, the else if (hasAppDir) block that checked for missing type glob patterns in existing include arrays was removed as part of refactoring to use imports in next-env.d.ts instead. However, the code failed to ensure next-env.d.ts itself is in the include array for projects with custom configurations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't look like we checked that before so I won't change it just yet. Maybe we told people that they can remove next-env.d.ts from include to opt-out of Next.js specific type-checking.

@eps1lon eps1lon changed the base branch from canary to graphite-base/87319 December 18, 2025 22:33
@eps1lon eps1lon force-pushed the graphite-base/87319 branch from 26cde21 to 987ea40 Compare December 18, 2025 22:33
@eps1lon eps1lon force-pushed the sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded branch from 6ae7a6b to f68128f Compare December 18, 2025 22:33
@eps1lon eps1lon changed the base branch from graphite-base/87319 to sebbie/12-18-validate_module_shape_of_pages_api_routes_with_actual_pageconfig_type December 18, 2025 22:33
Copy link
Member Author

eps1lon commented Dec 18, 2025

This stack of pull requests is managed by Graphite. Learn more about stacking.

@eps1lon eps1lon changed the base branch from sebbie/12-18-validate_module_shape_of_pages_api_routes_with_actual_pageconfig_type to graphite-base/87319 December 18, 2025 23:02
@eps1lon eps1lon force-pushed the sebbie/12-18-ensure_chache_profiles_and_routes_are_type-checked_even_if_.next_is_excluded branch from f68128f to 4d03cbb Compare December 18, 2025 23:02
@eps1lon eps1lon force-pushed the graphite-base/87319 branch from 987ea40 to 26cde21 Compare December 18, 2025 23:02
@eps1lon eps1lon changed the base branch from graphite-base/87319 to canary December 18, 2025 23:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

create-next-app Related to our CLI tool for quickly starting a new Next.js application. created-by: Next.js team PRs by the Next.js team. Documentation Related to Next.js' official documentation. tests type: next

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants