Next.js Engine v2.6.1 — React 19, Hydration & App Router Stability
Release type: Patch / stability update Base release: v2.6.0 Recommended tag:
Release-v2.6.1Focus: React 19 hydration correctness, Next.js 16 App Router behavior, routing consistency, style determinism, Overlay correctness, and regression coverage.
v2.6.1 is a stability-focused follow-up to the large v2.6.0 feature release. It does not introduce another major subsystem. Instead, it hardens the systems added or substantially changed around v2.6.0 so they behave correctly under React 19 concurrent rendering, Next.js 16 SSR/hydration, App Router navigation, rewrites, Suspense, Fast Refresh, and nested Engine composition.
The biggest theme of this release is simple:
Server output and the first client render should agree.
That sounds obvious, but React 19 and the App Router are much less forgiving of render-time mutation, browser-only decisions during initial render, invalid interactive HTML, and routing state that differs between the server and browser.
Highlights
- Fixes the primitive style precedence bug that could turn explicitly dark Cards white or override schema Button/Text styling.
- Hardens Engine-generated CSS against SSR/client ordering differences and React concurrent rendering.
- Makes initially-open Dialog, Drawer, and Popover surfaces hydration-safe.
- Makes legacy EngineScroll reduced-motion behavior hydration-safe.
- Makes EngineNav active-route styling safe around Next.js rewrites and fixes route-prefix false positives.
- Unifies internal primitive navigation with Next.js routing instead of falling back to full-document
<a>navigation. - Detects/suppresses invalid nested interactive surfaces that could cause browser DOM repair before React hydrates.
- Removes global Engine shimmer-keyframe collisions and improves static stylesheet/HMR behavior.
- Improves React 19 stylesheet-resource integration for Engine styles and theme fonts.
- Fixes live Overlay body-scroll locking when
lockScrollchanges while open. - Hardens EngineShader development hot-reload polling/listener isolation.
- Adds hydration-focused regression coverage so these bugs can fail CI instead of only appearing in consuming applications.
1. Primitive style precedence fixed
A major styling bug was discovered in the primitive layer.
Primitive defaults and variant styles were being passed through the same override slot used for explicit style={} values. Because that extra style object won over resolved Engine props, component defaults could silently defeat the public schema styling API.
For example:
{
type: "card",
props: {
bg: "#0b0d10",
borderRadius: "20px",
},
}could incorrectly resolve to the Card defaults:
background: #fff;
border-radius: 12px;Button variant colors and Text/Heading variant typography could be affected by the same precedence inversion.
New precedence contract
The primitive styling model is now explicitly:
component defaults
<
semantic / variant defaults
<
Engine schema props
<
explicit style={}
<
required runtime stateThis means:
card.props.bgbeats the Card variant background;card.props.borderRadiusbeats the default radius;- Button
bg,color, andfontWeightbeat variant defaults; - Text/Heading
fontSizeandfontWeightbeat variant typography defaults; - explicit
style={}still wins over schema styling; - runtime-enforced states such as disabled behavior may still win when required for correctness.
The fix uses a dedicated layered primitive-style helper rather than reversing usePropStyles() globally, which would have broken the intended style={} override contract.
Affected primitive/component families were audited, including Stack, Grid, Text/Heading, Section, Button, Card, Hero, Markdown, CustomSelect, Dialog, Drawer, and Popover.
2. Engine style collection and hydration stability
React 19 can interrupt, restart, suspend, and replay render work. Engine-generated styles must therefore not depend on accidental render traversal order or on mutations from work React later abandons.
The v2.6.x scoped StyleCollector architecture exposed a hydration failure where the server and browser could produce semantically equivalent CSS in a different insertion order. React compares <style> text during hydration, so even an ordering-only difference can produce a hydration warning.
The failure was especially visible with nested Engine boundaries such as:
createComponent() chrome
└── createPage() page
└── nested provider-scoped generated stylesand with Suspense/lazy split components that can resolve in a different render schedule.
v2.6.1 direction
Generated Engine CSS is hardened around deterministic snapshots and stable resource identity rather than relying on incidental traversal order.
The goal is that equivalent Engine inputs produce equivalent first-render CSS regardless of whether React rendered a subtree synchronously, retried it, or suspended another subtree nearby.
This patch also adds hydration-specific regression coverage using real server rendering followed by hydrateRoot() instead of relying only on type-check/build smoke tests.
3. Initially-open Overlay hydration
EngineDialog, EngineDrawer, and EnginePopover support controlled and uncontrolled initial open state.
Previously, an initially-open Overlay could evaluate the portal target during render:
const target = typeof document !== "undefined"
? document.body
: null;That produces different initial trees:
SSR:
trigger
(no portal)
first browser render:
trigger
+ portal in document.bodyv2.6.1 makes portal activation hydration-stable. The server output and the first browser render agree, then the portal is activated after the client has mounted.
This preserves SSR rather than solving the problem by disabling server rendering for Overlay components.
4. Overlay live scroll-lock correctness
Overlay behavior uses reference-counted body scroll locking so multiple modal surfaces can coexist.
A state-lifecycle bug meant lockScroll was only consulted when the main Overlay behavior effect started. If an open Overlay changed from:
lockScroll=trueto:
lockScroll=falsethe body could remain locked until the Overlay closed.
v2.6.1 moves scroll locking into a lifecycle that reacts to the live lockScroll state while preserving nested-overlay reference counting.
5. Legacy EngineScroll reduced-motion hydration
The older schema scroll component could read browser reduced-motion capability during render.
On the server, EngineBrowser intentionally has no access to matchMedia() and reports a stable server fallback. In the browser, prefers-reduced-motion may immediately resolve differently.
That could make SSR output include transition/smooth-scroll styles while the first client render removed them, producing a hydration disagreement for users with reduced motion enabled.
v2.6.1 makes the initial render deterministic and applies browser preference after hydration, with CSS media-query behavior preferred where practical.
6. EngineNav rewrite-safe hydration
EngineNav uses the current pathname to calculate active navigation state.
With Next.js App Router rewrites, the pathname used during prerendering can differ from the browser-visible pathname. If active-route state directly changes generated classes during the first render, the server and client can disagree.
In NE this could affect:
fontWeight;- active text color;
- active background;
- generated static class identity;
- collected CSS content.
v2.6.1 keeps initial Nav output hydration-stable, then applies browser route-active decoration after mount when needed.
The links themselves remain fully SSR-rendered and navigable.
7. EngineNav route matching fixed
The old active-route test relied on a simple prefix check.
That could incorrectly treat these as the same route family:
/about -> /about-us
/product -> /productivity
/docs -> /docs-oldRoute matching now respects segment boundaries.
Expected behavior:
/about matches /about
/about matches /about/team
/about does NOT match /about-usThe root route continues to receive its own special handling.
8. Internal primitive links now use the Next.js routing pipeline
Several linked primitives historically wrapped themselves with a raw <a href> even for same-origin application routes.
That meant:
{
type: "card",
props: {
href: "/product",
},
}could perform a full document navigation while an EngineLink pointing at the same route used the App Router.
v2.6.1 consolidates Engine navigation behavior around one routing policy:
external / protocol / _blank
→ native <a>
normal internal route
→ next/link
animated internal route
→ EngineTransitions+ / EngineTransitionLinkThis keeps client-side layout state, Next.js prefetch/navigation behavior, and Transitions+ integration consistent across Engine surfaces.
9. Nested interactive HTML protection
An href-enabled Box/Card/Text/Section/Hero can contain child content that is itself interactive.
Without protection, a schema can accidentally produce invalid HTML such as:
<a href="/parent">
<p>
<a href="/child">Child link</a>
</p>
</a>or an anchor surface containing Buttons/forms/other links.
Browsers are allowed to repair invalid interactive nesting before React hydrates. The DOM React sees is then not necessarily the DOM the server emitted, which can trigger hydration failure.
v2.6.1 hardens linked surfaces so invalid outer interactive wrappers are not emitted when nested interactive content is detected.
The schema analyzer also gains a dedicated advisory diagnostic for this class of mistake so applications can catch it during development/CI rather than discovering it from a browser hydration warning.
10. Engine shimmer/keyframe collision fixed
Multiple Engine systems independently defined the same global animation name:
@keyframes e-shimmerbut with different keyframes.
Affected areas included loading/lazy surfaces such as LazyMount, EngineImage, and EngineSuspense.
CSS keyframe names are global, so whichever definition was inserted last could silently change another component's animation.
v2.6.1 separates animation ownership and/or routes shared animations through one canonical definition so one subsystem can no longer redefine another subsystem's shimmer behavior.
11. Static Engine CSS and Fast Refresh hardening
Some component-level static CSS was historically injected after mount with imperative code like:
document.head.appendChild(style);That has two drawbacks:
- SSR can reference an animation/class before its static stylesheet exists.
- Fast Refresh can re-evaluate modules and append duplicate style elements when the only guard is a module-level boolean.
v2.6.1 moves common Engine runtime CSS toward deterministic, stable stylesheet resources with reusable IDs/identity and SSR-compatible placement.
This reduces flash-of-unstyled behavior and duplicate stylesheet buildup during development.
12. React 19 stylesheet-resource integration
React 19 can coordinate stylesheet resources when stylesheet links/styles have stable precedence metadata.
Engine-generated styles and theme font stylesheets are updated to cooperate with this model instead of behaving like arbitrary component-local <link> or <style> elements.
This improves:
- resource deduplication;
- stable head placement;
- stylesheet ordering;
- nested Engine component behavior;
- compatibility with React 19 rendering semantics.
Nested Engine themes also avoid relying on one fixed global DOM id for every theme stylesheet.
13. App Router handler/config boundary clarified
NE intentionally supports server-first schema pages, but Next.js App Router does not allow arbitrary JavaScript functions to be serialized from a Server Component into a Client Component.
That matters for APIs such as:
createPage({
schema,
handlers: {
doSomething: () => {},
},
});and custom function-valued configuration such as a custom spacingScale when those values originate in a Server Component module and cross into the client provider.
v2.6.1 documentation makes this boundary explicit rather than pretending Next.js can serialize arbitrary callbacks.
The fix does not turn every Engine page into a Client Component and does not serialize/evaluate function source.
The intended architecture remains:
serializable schema/server configuration
→ server-first Engine rendering
browser callbacks / interactive handler registry
→ explicit Client Component boundary
server actions / server-only data work
→ Next.js server boundaryThis preserves the point of NE instead of fighting React Server Components.
14. EngineShader development hot-reload hardening
The EngineShader development runtime received additional race protection after the main v2.6.0 Shader work.
The development manifest poller is serialized so a new forced poll does not start while the previous poll is still in flight.
Hot-reload listener notification is also isolated: one failing listener no longer prevents other live Shader surfaces from receiving the update.
Regression coverage includes:
- overlapping poll ticks;
- listener failure isolation;
- subsequent successful polls;
- unchanged manifest revisions;
- recovery after an initial manifest load failure.
This is primarily a development-stability fix and does not change the .shed authoring API.
15. Regression testing expanded for hydration
A normal production build can succeed while an application still throws a hydration warning at runtime.
v2.6.1 therefore expands the test strategy beyond compile/type/build checks.
Hydration-focused tests are designed to cover:
- server rendering followed by
hydrateRoot(); - nested
createComponent()+createPage()Engine boundaries; - generated responsive/static CSS stability;
- initially-open Dialog/Drawer/Popover behavior;
- Overlay scroll-lock changes while mounted;
- rewrite/pathname-sensitive Nav rendering;
- route segment matching;
- nested interactive/link composition.
The important behavior is that onRecoverableError should remain silent for supported Engine compositions.
Compatibility
v2.6.1 is intended as a patch release and does not deliberately remove the v2.6.0 public feature set.
Existing v2.6.0 systems remain:
- EngineShader and
.shed; - EngineTransitions+ and its 20 presets;
- advanced EngineScroll timelines/ranges/director;
- EngineOverlay Dialog/Drawer/Popover;
- EngineCanvas / EngineSVG / Engine3D retained rendering;
- EngineAPI / APIStatic;
- EngineBrowser / EngineDevice / Mobile patching;
- current schema and styling APIs.
Behavior may become stricter when NE detects invalid nested interactive markup. That is a correctness fix: the previous output could be invalid HTML and hydration-unsafe.
No fake fixes
Several tempting workarounds are intentionally not part of v2.6.1:
- no blanket
suppressHydrationWarning; - no disabling SSR for the whole Engine;
- no
typeof window !== "undefined"branches that deliberately change first-render markup; - no converting every page to
"use client"; - no function serialization/eval hacks for App Router handlers;
- no removal of Engine lazy/Suspense behavior just to make ordering easier;
- no removal of Transitions+, Overlay, or Engine-generated responsive CSS.
The patch is meant to make those systems compatible with modern React/Next behavior without destroying why they exist.
Suggested GitHub release summary
Next.js Engine v2.6.1 — React 19, Hydration & App Router Stability
A stability patch for the v2.6 generation. v2.6.1 fixes primitive style precedence, SSR/client generated-style mismatches, initially-open Overlay hydration, reduced-motion hydration, rewrite-sensitive Nav state, route-prefix matching, invalid nested interactive markup, primitive internal routing, global shimmer collisions, development stylesheet duplication, React 19 stylesheet integration, live Overlay scroll locking, and EngineShader hot-reload polling races. It also adds hydration-focused regression coverage so runtime SSR→client mismatches can fail CI instead of only appearing inside consuming applications.
Publication checklist
Before publishing the official GitHub release/tag:
- Land the complete v2.6.1 stability implementation on
main. - Run the hydration regression suite successfully.
- Run the existing Engine runtime CI successfully.
- Run TypeScript type-check successfully.
- Run the full Next.js 16 production integration build successfully.
- Confirm
main-emptysynchronization. - Set workspace/package metadata to
2.6.1where applicable. - Verify the distributable package contains the v2.6.1 docs.
- Create tag
Release-v2.6.1. - Publish the GitHub release using this document as the detailed changelog.
Release positioning
v2.6.0 was the large feature release: Shader, Motion, Scroll, and Overlay.
v2.6.1 is the follow-up that makes those capabilities substantially safer under the realities of React 19 and Next.js 16.
v2.6.0
→ new capabilities
v2.6.1
→ hydration, routing, style, runtime, and development stability