Today we are introducing @master/css.next, the official Master CSS integration for Next.js.
The headline is Progressive Rendering through the Next.js Adapter API. The adapter plugs into the Next.js build pipeline, receives the final static and pre-rendered HTML outputs, renders the Master CSS rules each document needs, and writes them back into the page as <style id="master-css">.
This release also includes Static Rendering for Turbopack, so teams that prefer a generated CSS asset can use a source-scanned workflow. That path is useful, but it is secondary to the larger integration: Master CSS can now render from the HTML that Next.js actually produced.
Why this release matters
Next.js 16.2 introduced a stable Adapter API. In the Next.js team's words, the build now exposes a typed, versioned description of the application, including routes, prerenders, static assets, runtime targets, dependencies, caching rules, and routing decisions.
That gives Master CSS a better integration point than a post-build file glob. @master/css.next uses the public onBuildComplete hook to read the final build output and process the HTML that Next.js already knows about.
For App Router applications, Server Components, MDX, generated pages, static routes, and pre-rendered routes, this matters because the adapter works from the framework output instead of guessing how the build directory is shaped.
Progressive Rendering in Next.js
Master CSS is markup-driven. The class string is the styling source of truth:
export default function Page() { return ( <main className="min-h:100vh p:10x bg:surface-base text:neutral"> <h1 className="font:48px font:heavy tracking:tight"> Master CSS pre-rendered by Next.js </h1> </main> )}In runtime mode, Master CSS reads those classes in the browser and generates the matching CSS immediately. That keeps authoring flexible, but the first document still depends on JavaScript before every first-render style is available.
Progressive Rendering moves that first CSS pass into the build:
- Next.js renders static and pre-rendered HTML during
next build. @master/css.nextreceives those build outputs through the Adapter API.- The adapter runs the Master CSS server renderer against each HTML document.
- The generated CSS is injected as
<style id="master-css">, and the page hydration manifest is written as a hashed JSON asset. - The style tag receives
data-master-css-hydration-manifest, and the runtime imports that manifest during hydration to attach existing CSS rules to runtime-managed rule objects instead of regenerating them.
The result is a page that can arrive from the server already carrying the CSS needed for its first render, while still keeping the runtime behavior that makes Master CSS practical in interactive applications. If the hydration manifest is missing, invalid, or no longer matches style#master-css, the runtime safely rebuilds its stylesheet from the connected DOM classes.
Hydration manifest hydration
Progressive Rendering is not only a critical CSS optimization. It is also a resumable runtime handoff.
style#master-css gives the browser the CSS it needs to paint immediately. style#master-css[data-master-css-hydration-manifest] points the Master CSS runtime to a compact JSON rule IR, currently version: 1, that describes the generated rules inside that style block. Each manifest rule can include the class name, layer, priority, selector text, generated CSS text, and any referenced variables or animations.
That distinction matters because the runtime needs to keep managing the page after hydration. A client component may mount later, a class may change in response to state, or a route transition may reveal UI that did not exist in the first HTML document. The manifest lets the runtime adopt the already-rendered rules as its starting point, then continue from there without duplicating the CSS that the build already wrote. Keeping that manifest external preserves the first-paint benefit of inline CSS while reducing HTML transfer and parse pressure on pages with many generated rules.
For a minimal page:
export default function Page() { return <h1 className="font:48px">Hello</h1>}Progressive Rendering produces HTML shaped like this:
<!doctype html><html><head> <style id="master-css" data-master-css-hydration-manifest="/_next/static/master-css/hydration/master-css-hydration.8f3a1c2d.json">@layer utilities{.font\:48px{font-size:48px}}</style></head><body> <h1 class="font:48px">Hello</h1></body></html>The browser can paint the heading from style#master-css before the runtime does any work. When the runtime starts, it imports the hashed JSON manifest, maps the native CSS rule back to font:48px, and continues handling later dynamic classes from the same managed stylesheet. If a page has no generated Master CSS rules, the adapter does not need to attach a manifest URL.
This page hydration manifest is separate from the project manifest and from the manifest option in @master/css.next. When enabled, the Next adapter option writes .next/master-css-manifest.json as a build report for rendered files; it is not the route-level JSON used to hydrate style#master-css in the browser.
Adapter integration
The new adapter is registered in next.config.js, and Next.js calls it when the full build output is available:
import { withMasterCSS } from '@master/css.next'/** @type {import('next').NextConfig} */const nextConfig = withMasterCSS({ // your Next.js config})export default nextConfigThis turns Progressive Rendering from a post-build convention into a framework-level integration. Master CSS no longer needs the application to maintain a second render script, and the integration can follow the typed Next.js output contract as it evolves.
What improves
Faster first paint
The critical CSS for a pre-rendered page is already in the HTML response. The browser does not need to wait for the Master CSS runtime to boot before styling the first screen, which reduces the risk of flash of unstyled content.
Route-level CSS output
The adapter renders CSS from each HTML document, not from the entire source tree. A page only receives the class rules needed by that page's first HTML output.
That is especially valuable for documentation sites, marketing pages, blogs, dashboards with static shells, and large App Router applications where different routes use very different surfaces.
Runtime flexibility stays available
Progressive Rendering does not remove the runtime engine. It gives the first response the CSS that can be known during the build, then lets the runtime continue tracking client-only state, late UI, and dynamic class names after hydration.
Same authoring model
There is no second syntax and no separate critical CSS file to maintain. You still write Master CSS classes in markup, and the adapter decides what should be present in the first HTML response.
Install it
For the full setup, follow Progressive Rendering in Next.js. If your project needs a source-scanned CSS build instead, use Static Rendering in Next.js.
Import Master CSS from the stylesheet your app already loads. This stylesheet also serves as the project CSS entry:
@import '@master/css';Install the React runtime provider and the Next.js adapter:
npm i @master/css.react@rc @master/css.next@rcWrap the root layout with the React runtime registry:
import './globals.css'import { CSSRuntimeRegistry } from '@master/css.react'export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="en" hidden={process.env.NODE_ENV === 'development'}> <body> <CSSRuntimeRegistry> {children} </CSSRuntimeRegistry> </body> </html> )}CSSRuntimeRegistry loads the canonical project-level MasterCSSManifest compiled by the Next.js adapter.
Then register the adapter:
import { withMasterCSS } from '@master/css.next'/** @type {import('next').NextConfig} */const nextConfig = withMasterCSS({ /* your Next.js config */})export default nextConfigDevelopment uses the runtime engine directly for fast refresh. Run a production build to verify that <style id="master-css"> is pre-rendered into static and pre-rendered HTML outputs:
npm run buildnpm run startStatic Rendering for Turbopack
@master/css.next also supports a source-scanned CSS workflow for projects that do not need runtime rendering or route-level HTML pre-rendering.
Static mode uses the same Master CSS stylesheet import model as the other build integrations:
@import '@master/css';.main { background-color: var(--color-primary);}@theme { --color-primary: #ff0000;}Then enable static mode in next.config.js:
import { withMasterCSS } from '@master/css.next'/** @type {import('next').NextConfig} */const nextConfig = await withMasterCSS({ // your Next.js config}, { mode: 'static'})export default nextConfigUnder the hood, static mode scans the configured source files with @master/css-scanner and writes a generated CSS file under .master/. A Turbopack CSS loader replaces @import "@master/css" with that generated CSS, and stylesheets that import @master/css are treated as native CSS pruning roots by default.
Ordinary class selectors in those roots are pruned against detected classes. References to var(--*) or manifest animation names can pull matching variables and keyframes from the project CSS entry graph. During Turbopack builds, a scanner loader also reads JavaScript and TypeScript modules that pass through the module graph, so imported files can incrementally feed additional class names into the scanner.
This mode is intentionally source-scanned. It works best when complete class strings are visible in source files, and source-glob scanning remains the production correctness baseline.
Different from Tailwind CSS
The useful comparison is not that source scanning is radically different. In static mode, Master CSS and Tailwind CSS have a similar constraint: the scanner needs complete class names that are visible in source.
Tailwind detects classes by scanning source files as plain text, then generates CSS for the utilities it can detect. Master CSS Static Rendering for Next.js follows the same general shape-outside: scan source, generate CSS, and let the build load that generated stylesheet.
The larger difference is Progressive Rendering.
With @master/css.next, the first CSS pass can start from the HTML that Next.js has already rendered. That means layout composition, MDX output, generated markup, Server Component output, and route-level rendering all converge into one artifact before Master CSS renders the page CSS.
For source scanning, a dynamic class still needs to resolve to complete class strings in source. For Progressive Rendering, a pre-rendered route can produce the final class list in HTML first:
export function Badge({ tone }: { tone: 'blue' | 'neutral'}) { return ( <span className={`r:4px px:2x py:1x text:${tone} bg:${tone}/.1`}> New </span> )}If a pre-rendered route outputs this HTML:
<span class="r:4px px:2x py:1x text:blue bg:blue/.1">New</span>@master/css.next reads that final class list from the generated document and injects the matching CSS for the first response. The runtime can then continue covering client-only and dynamic UI after hydration.
The practical difference:
- In static mode, Master CSS and Tailwind CSS both depend on statically discoverable source classes.
- Tailwind CSS focuses on a compile-time stylesheet generated from source detection.
- Master CSS Next.js can instead use Progressive Rendering to inline first-render CSS from Next.js HTML output.
- The Master CSS runtime remains available for UI that cannot be known at build time.
This is a different tradeoff, not a claim that one pipeline replaces the other. Tailwind CSS is a mature compile-time CSS framework. Master CSS is a runtime-capable CSS engine with build-time Progressive Rendering. The Next.js Adapter makes that hybrid model feel native in a Next.js application.
Current boundary
@master/css.next is a build-time adapter. It processes static and pre-rendered HTML outputs produced during next build.
Dynamic SSR responses still rely on the Master CSS runtime engine, because those responses are produced at request time rather than in the completed build output. This is intentional: the first HTML response gets the CSS that can be known at build time, and the runtime continues the rendering model where the page becomes dynamic.
In static mode, the generated CSS asset comes from source scanning. It works best when the complete class strings are visible in source files. The Turbopack scanner loader improves incremental updates for modules that pass through the build, but source-glob scanning remains the production correctness baseline.
If another integration already owns Next.js adapterPath, use runtime mode until adapter composition is available.
A better foundation for Next.js
The important change is not just that the setup is shorter. It is that Master CSS now integrates with the same public build contract Next.js is using to support adapters across platforms.
That gives the integration a better long-term shape-outside:
- it is tied to a typed Next.js output contract;
- it runs when all static and pre-rendered outputs are known;
- it removes file-glob assumptions from the user setup;
- it keeps runtime rendering available for the parts of the UI that cannot be known at build time;
- it makes Progressive Rendering the default story for serious Next.js projects.
Master CSS has always treated markup as the styling interface. With the Next.js Adapter, the final HTML document becomes the bridge between Next.js rendering and Master CSS generation.
That is exactly where Progressive Rendering belongs.