vercel / vercel/next.js

experimental.inlineCss duplicates the full CSS bundle into every RSC/segment payload (standalone build-output bloat)

Open
#95,141 2 comments 3 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Output
Dominant language
JavaScript
Stars
142k
Forks
32.5k
Avg merge
2d 14h
Merged PRs (30d)
351

Description

Link to the code that reproduces this issue

https://github.com/mikaelh/next-inlinecss-rsc-dup-repro

To Reproduce
  1. npm install (pulls next@canary) then npm run build on the linked repo. It is a minimal App Router app: output: "standalone", experimental.inlineCss: true, a 155 KB global stylesheet imported in the root layout, and one [slug] route with generateStaticParams → 60 tiny static pages.
  2. Inspect .next/standalone/.next/server/app, e.g. grep -rl '\.u1000{' .next/standalone/.next/server/app | wc -l and count occurrences per file.
Current vs. Expected behavior

Current (verified on next@16.3.0-canary.66): with inlineCss, the whole stylesheet is inlined into each page's HTML <style> and also serialized into the page's RSC payloads — the inline flight inside the .html, the page.rsc, and each .segments/*.segment.rsc.

Observed in the repro for one trivial static page (a1.html, 411 KB for "tiny content"): 1 <style> block, but the CSS marker rule appears (<style> + flight). Across the build the 155 KB CSS is embedded in 62 .html, 186 .rsc (of which 124 are *.segments/*.segment.rsc) → .next/server/app = 69 MB for 60 pages of "tiny content". So each prerendered page stores the stylesheet ~3–4× (HTML <style> + HTML flight + page.rsc + each segment.rsc); build output scales with CSS_size × pages × ~4.

Amplifier: moving the @import from the root layout into a nested layout (route group) makes the per-segment copies multiply (~2× → ~5× per page in a larger app), so per-route CSS scoping is counter-productive under inlineCss. On a real content site (~700 prerendered pages, 172 KB CSS) the duplicated CSS is ~205 MB of a 453 MB server/app; moving CSS to a nested layout took server/app from 453 MB to 868 MB.

Expected: inlined CSS referenced/deduplicated once per prerendered page rather than copied into every RSC/segment payload. The segment-cache / client-navigation RSC payloads don't need the full stylesheet embedded — on client navigation the browser already has the styles applied. Keep inlining into the initial HTML (the FCP/LCP win) without duplicating across the RSC.

Provide environment information
Operating System: Linux
Binaries:
  Node: 24.x
Relevant Packages:
  next: 16.3.0-canary.66
  react: 19.2.0
  react-dom: 19.2.0
Next.js Config:
  output: "standalone"
  experimental.inlineCss: true
Which area(s) are affected? (Select all that apply)

Output (Standalone), Partial Prerendering (PPR)

Which stage(s) are affected? (Select all that apply)

next build (local)

Additional context

inlineCss is otherwise a real FCP/LCP win, so disabling it is an unwanted trade-off — the request is to keep the initial-HTML inline but stop duplicating the bundle across the RSC/segment payloads. Measured via du + counting the inlined CSS chunk across .html / .rsc / .segments/*.segment.rsc. (Supersedes #95140, which was auto-closed for a parsing issue — the reproduction link is now in the correct field.)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the linked reproduction with npm install and npm run build, then inspect .next/standalone/.next/server/app, including the generated .html, .rsc, and .segments/*.segment.rsc files. Trace experimental.inlineCss through the build output and RSC payload generation; done means CSS remains in the initial HTML without being duplicated across the page and segment payloads.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, next.js, react
Domain
build-system, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.