Problem
For auto-exported dynamic Pages routes (e.g. /posts/[id] with no data-fetching), Next.js renders with router.query === {} while router.isReady === false, then fills query after hydration. vinext renders with a fully-populated router.query while isReady is false, violating the Next.js invariant that query is empty until isReady. App code written against Next.js (e.g. guarding data fetches on router.isReady and assuming router.query.id is absent during the not-ready phase, or rendering a skeleton) behaves differently under vinext. Client and server are internally consistent (no hydration mismatch within vinext), so impact is a behavioral parity gap rather than a crash.
Evidence
packages/vinext/src/server/pages-page-handler.ts:416 — applySSRContext publishes the full merged query (route params + querystring) into the SSR router context unconditionally, including for autoExport dynamic pages where navigationIsReady is computed as false.
packages/vinext/src/shims/router.ts:749 — The SSR branch of getPathnameAndQuery returns _ssrCtx.query verbatim with no readiness gate, so useRouter().query is fully populated even when router.isReady is false.
packages/vinext/.nextjs-ref/packages/next/src/server/render.tsx:641 — Next.js sets query = {} for isAutoExport || isFallback renders, so on an autoExport dynamic page the server (and the not-ready client) render with an empty router.query until the client router becomes ready.
Next.js behavior (Next.js handles this correctly — vinext-only bug)
I traced the exact autoExport-dynamic Pages scenario (e.g. /posts/[id] with no data fetching) through Next.js. In dev, render.tsx:639-641 resets query={} for isAutoExport||isFallback before it reaches ServerRouter and NEXT_DATA.query (render.tsx:712,1495), so the SSR HTML carries an empty query. In production, such pages are not prerendered with concrete params (no getStaticPaths) and are served as auto-export shells; the client router constructor (router.ts:807-826) computes autoExportDynamic from NEXT_DATA.autoExport, initializes isReady=false, and sets state.query to the param-less initialData.query (client/index.tsx:961). Route params are only merged into query and isReady flipped to true inside componentDidMount via router.replace(...,{_h:1}) (client/index.tsx:115-157, router.ts:1233-1234). The canonical router-is-ready test asserts isReadyValues===[false,true] for a dynamic auto-export page in BOTH development and production modes, confirming Next.js renders with empty router.query while isReady===false and populates it only after hydration. vinext's applySSRContext (pages-page-handler.ts:416) publishes the fully merged query unconditionally while navigationIsReady is false, and the SSR branch of getPathnameAndQuery (router.ts:749) returns it verbatim, so the defect is vinext-only.
Citations: packages/next/src/server/render.tsx:639-641 (dev: query={} for isAutoExport||isFallback); packages/next/src/shared/lib/router/router.ts:807-808 + 818-826 + 838-846 (autoExportDynamic => isReady=false, state.query=initialData.query); packages/next/src/client/index.tsx:961 (router created with initialData.query) and 115-157 (componentDidMount router.replace _h:1 populates query); packages/next/src/shared/lib/router/router.ts:1233-1234 (isReady flips true on query update); test/integration/router-is-ready/test/index.test.ts:60-68 + 81-110 (asserts [false,true] for dynamic auto-export page, run in
Suggested fix
When the route is autoExport-dynamic (or fallback) and not ready, surface an empty query for the next/router useRouter() SSR/initial snapshot to match Next.js's query = {} carve-out, while still recovering full query once the router publishes ready state — mirroring the readiness gating already applied to the next/navigation compat hooks in getPagesNavigationContext.
Test plan
Port test/integration/router-is-ready cases: autoExport dynamic page sees query {} + isReady false, then full query + true.
Related / notes
Do after the NEXT_DATA.query fix (same files, coupled semantics). The next/navigation compat hooks already gate on readiness (router.ts:571-576) — mirror that for next/router.
Found via a deep source audit of main @ fd10233 (2026-06-12). Behavior parity-checked against Next.js v16.3.0-canary.7 source; citations above reference packages/next/src/... in the Next.js repo. Screened against all open issues/PRs as of 2026-06-12 to avoid duplicating tracked work.
Problem
For auto-exported dynamic Pages routes (e.g. /posts/[id] with no data-fetching), Next.js renders with router.query === {} while router.isReady === false, then fills query after hydration. vinext renders with a fully-populated router.query while isReady is false, violating the Next.js invariant that query is empty until isReady. App code written against Next.js (e.g. guarding data fetches on
router.isReadyand assumingrouter.query.idis absent during the not-ready phase, or rendering a skeleton) behaves differently under vinext. Client and server are internally consistent (no hydration mismatch within vinext), so impact is a behavioral parity gap rather than a crash.Evidence
packages/vinext/src/server/pages-page-handler.ts:416— applySSRContext publishes the full mergedquery(route params + querystring) into the SSR router context unconditionally, including for autoExport dynamic pages where navigationIsReady is computed as false.packages/vinext/src/shims/router.ts:749— The SSR branch of getPathnameAndQuery returns _ssrCtx.query verbatim with no readiness gate, so useRouter().query is fully populated even when router.isReady is false.packages/vinext/.nextjs-ref/packages/next/src/server/render.tsx:641— Next.js setsquery = {}for isAutoExport || isFallback renders, so on an autoExport dynamic page the server (and the not-ready client) render with an empty router.query until the client router becomes ready.Next.js behavior (Next.js handles this correctly — vinext-only bug)
I traced the exact autoExport-dynamic Pages scenario (e.g. /posts/[id] with no data fetching) through Next.js. In dev, render.tsx:639-641 resets query={} for isAutoExport||isFallback before it reaches ServerRouter and NEXT_DATA.query (render.tsx:712,1495), so the SSR HTML carries an empty query. In production, such pages are not prerendered with concrete params (no getStaticPaths) and are served as auto-export shells; the client router constructor (router.ts:807-826) computes autoExportDynamic from NEXT_DATA.autoExport, initializes isReady=false, and sets state.query to the param-less initialData.query (client/index.tsx:961). Route params are only merged into query and isReady flipped to true inside componentDidMount via router.replace(...,{_h:1}) (client/index.tsx:115-157, router.ts:1233-1234). The canonical router-is-ready test asserts isReadyValues===[false,true] for a dynamic auto-export page in BOTH development and production modes, confirming Next.js renders with empty router.query while isReady===false and populates it only after hydration. vinext's applySSRContext (pages-page-handler.ts:416) publishes the fully merged query unconditionally while navigationIsReady is false, and the SSR branch of getPathnameAndQuery (router.ts:749) returns it verbatim, so the defect is vinext-only.
Citations: packages/next/src/server/render.tsx:639-641 (dev: query={} for isAutoExport||isFallback); packages/next/src/shared/lib/router/router.ts:807-808 + 818-826 + 838-846 (autoExportDynamic => isReady=false, state.query=initialData.query); packages/next/src/client/index.tsx:961 (router created with initialData.query) and 115-157 (componentDidMount router.replace _h:1 populates query); packages/next/src/shared/lib/router/router.ts:1233-1234 (isReady flips true on query update); test/integration/router-is-ready/test/index.test.ts:60-68 + 81-110 (asserts [false,true] for dynamic auto-export page, run in
Suggested fix
When the route is autoExport-dynamic (or fallback) and not ready, surface an empty query for the next/router useRouter() SSR/initial snapshot to match Next.js's
query = {}carve-out, while still recovering full query once the router publishes ready state — mirroring the readiness gating already applied to the next/navigation compat hooks in getPagesNavigationContext.Test plan
Port
test/integration/router-is-readycases: autoExport dynamic page sees query {} + isReady false, then full query + true.Related / notes
Do after the NEXT_DATA.query fix (same files, coupled semantics). The next/navigation compat hooks already gate on readiness (router.ts:571-576) — mirror that for next/router.
Found via a deep source audit of
main@ fd10233 (2026-06-12). Behavior parity-checked against Next.js v16.3.0-canary.7 source; citations above referencepackages/next/src/...in the Next.js repo. Screened against all open issues/PRs as of 2026-06-12 to avoid duplicating tracked work.