Skip to content

Support the typedRoutes config option (statically typed links) #3075

Description

@LukeHalby

Summary

Support the stable typedRoutes config option (statically typed links). vinext's typegen already generates .next/types/routes.d.ts with route unions and a ParamMap, which is most of the machinery — what's missing is the typed-links file Next.js emits when typedRoutes: true is set, plus wiring for the config flag. vinext check currently reports experimental.typedRoutes as unsupported, and the stable top-level typedRoutes key isn't in the config support map at all.

Motivation / problem

Apps that enable typedRoutes rely on import type { Route } from 'next' and compile-time validation of href values (e.g. lint/CI guards that keep internal links pointing at real routes). Migrating such an app to vinext silently loses the feature: the vendored Route<T> type stays the string & {} fallback stub, so everything type-checks whether or not the route exists. For codebases that use typed routes as a correctness gate rather than a convenience, this is a migration blocker.

Expected behaviour

With typedRoutes: true in next.config.*:

  • Dev, build, and vinext typegen additionally emit the typed-links declaration file (Next 16 writes .next/types/link.d.ts): the __next_route_internal_types__ namespace with StaticRoutes / DynamicRoutes / RouteImpl<T>, plus declare module augmentations for next (real Route<T>), next/link (typed href), next/navigation (typed useRouter, redirect, permanentRedirect), and next/form.
  • The generated next-env.d.ts references the new file alongside routes.d.ts.
  • vinext check reports typedRoutes as supported, with experimental.typedRoutes treated as a deprecated alias (matching Next, which stabilised the option).

Actual behaviour

  • The typedRoutes flag is not read anywhere; only routes.d.ts is generated.
  • Route<T> resolves to the vendored stub string & {}, so no href validation occurs.
  • check.ts lists experimental.typedRoutes as unsupported — typed routes not implemented; the stable key is absent from CONFIG_SUPPORT.

Reproduction context

Any Next.js 16 App Router project with typedRoutes: true in next.config.ts. Run vinext typegen (or dev/build) and observe that no typed-links declarations are generated and invalid <Link href="/does-not-exist"> values type-check. Observed against vinext main as of 2026-08-25 while scanning a six-app Next 16 monorepo for migration feasibility.

Additional context

Implementation sketch, from reading both codebases:

  • Next 16's reference implementation is compact: route-types-utils.js writes link.d.ts from generateLinkTypesFile(manifest) when config.typedRoutes === true. The template ports nearly verbatim, and typegen.ts's existing route model (patternToNextFormat) already produces Next-format patterns for the StaticRoutes / DynamicRoutes unions.
  • The vendored type tree (packages/types/next/upstream/dist/) already contains the modules the generated augmentations import from (dist/client/link.d.ts, dist/client/components/redirect-error.d.ts), so the emitted file should type-check without adapting the template's import paths.
  • Config plumbing: pass nextConfig.typedRoutes through the writeRouteTypes() call sites in index.ts and the typegen CLI path; warnDeprecatedConfigOptions is the existing hook for the experimental.typedRoutes alias.
  • Suggested scope for a first pass: App Router routes only (vinext's typegen currently models only the app dir). Next also folds Pages Router routes and redirect/rewrite sources into the generated unions — those, plus experimental.strictRouteTypes, could be deferred to follow-ups if that helps keep the first PR reviewable.
  • Tests would extend tests/typegen.test.ts's existing temp-project harness: static / dynamic / catch-all / route-group cases with the flag on, and a flag-off case asserting no typed-links file is emitted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions