nextjs - 💡(How to fix) Fix App Router final response drops User-Agent from Vary declared in next.config headers()

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Code Example

const PERSON_PROFILE_USER_AGENT_VARY_HEADERS = [
  {
    source: "/headers-only/:path*",
    headers: [
      {
        key: "Vary",
        value:
          "rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, User-Agent, Accept-Encoding",
      },
    ],
  },
];

const nextConfig = {
  cacheComponents: true,
  async headers() {
    return PERSON_PROFILE_USER_AGENT_VARY_HEADERS;
  },
};

export default nextConfig;

---

export async function generateStaticParams() {
  return [{ slug: "headers-only-target" }];
}

export default async function HeadersOnlyPage({ params }) {
  const { slug } = await params;
  return (
    <main>
      <h1>Headers-only route</h1>
      <p>Slug: {slug}</p>
      <p>This route exists only to test whether next.config headers survive to the final HTML response.</p>
    </main>
  );
}

---

export const metadata = {
  title: "Issue #1151 Repro",
  description: "Scratch Next.js 16 reproduction for comp990-web issue #1151.",
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

---

└ ◐ /headers-only/[slug]
/headers-only/[slug]

---

cache-control: s-maxage=31536000
vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, Accept-Encoding
x-nextjs-cache: HIT
x-nextjs-prerender: 1, 1

---

cache-control: private, no-cache, no-store, max-age=0, must-revalidate
vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, Accept-Encoding

---

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.x
Binaries:
  Node: 22.x
  npm: 10.x
Relevant Packages:
  next: 16.2.6
  react: 19.2.1
  react-dom: 19.2.1
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

I have a minimal self-contained repro app locally and can publish it if needed. The relevant files are small enough to include inline below.

To Reproduce

  1. Create a Next.js 16.2.6 App Router app with Cache Components enabled.
  2. Add a headers() rule in next.config.mjs for /headers-only/:path* that sets:
    • Vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, User-Agent, Accept-Encoding
  3. Add a single App Router page at /headers-only/[slug] with generateStaticParams() returning one slug.
  4. Run next build && next start.
  5. Request the same route with a browser UA, Googlebot UA, and Bingbot UA.
  6. Inspect the final response headers.

Current vs. Expected behavior

Expected:

  • The final HTML response for /headers-only/[slug] preserves the declared User-Agent token in Vary.

Current:

  • The final HTML response omits User-Agent from Vary.
  • The same simple route still varies behavior by UA:
    • browser: cache-control: s-maxage=31536000, x-nextjs-cache: HIT
    • Googlebot/Bingbot: cache-control: private, no-cache, no-store, max-age=0, must-revalidate

So the final response appears to be UA-sensitive while also dropping User-Agent from Vary.

Minimal repro files

next.config.mjs

const PERSON_PROFILE_USER_AGENT_VARY_HEADERS = [
  {
    source: "/headers-only/:path*",
    headers: [
      {
        key: "Vary",
        value:
          "rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, User-Agent, Accept-Encoding",
      },
    ],
  },
];

const nextConfig = {
  cacheComponents: true,
  async headers() {
    return PERSON_PROFILE_USER_AGENT_VARY_HEADERS;
  },
};

export default nextConfig;

app/headers-only/[slug]/page.js

export async function generateStaticParams() {
  return [{ slug: "headers-only-target" }];
}

export default async function HeadersOnlyPage({ params }) {
  const { slug } = await params;
  return (
    <main>
      <h1>Headers-only route</h1>
      <p>Slug: {slug}</p>
      <p>This route exists only to test whether next.config headers survive to the final HTML response.</p>
    </main>
  );
}

app/layout.js

export const metadata = {
  title: "Issue #1151 Repro",
  description: "Scratch Next.js 16 reproduction for comp990-web issue #1151.",
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

Observed local output

next build route summary:

└ ◐ /headers-only/[slug]
  ├ /headers-only/[slug]

Browser response headers:

cache-control: s-maxage=31536000
vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, Accept-Encoding
x-nextjs-cache: HIT
x-nextjs-prerender: 1, 1

Googlebot response headers:

cache-control: private, no-cache, no-store, max-age=0, must-revalidate
vary: rsc, next-router-state-tree, next-router-prefetch, next-router-segment-prefetch, Accept-Encoding

Bingbot response headers are the same as Googlebot for the relevant fields.

Additional context

  • This route does not use middleware/proxy.
  • It does not use generateMetadata().
  • It does not use nested layouts, wrappers, or app-specific data loaders.
  • The repro came from a larger production issue, but this minimal case already reproduces the Vary loss under local next build && next start.

Environment

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 24.x
Binaries:
  Node: 22.x
  npm: 10.x
Relevant Packages:
  next: 16.2.6
  react: 19.2.1
  react-dom: 19.2.1

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING