Generation 3 — Overview
Branch:
main-3This is the current Next.js Engine architecture. Start here before reading the older v1/v2 release notes or the large historical
DOCUMENT.mdreference.
The stack in one minute
Generation 3 turns a schema into a deterministic execution plan before deciding what the browser needs to own.
PageSchema
↓
compilePage()
↓
EngineCompiledPage / enginePlan
├─ runtime ownership: static / server / client
├─ work class: critical / visible / near / deferred / idle / sleeping
├─ used-feature manifest
├─ fallback plan
├─ asset graph
└─ diagnostics
↓
EngineServerRenderer
├─ durable HTML stays on the server
├─ browser behavior becomes narrow client islands
└─ server-rendered children can cross client-island boundaries
↓
EngineScheduler + EngineViewport + EngineModel
↓
optional network/security stack
EngineCommand / NENC / EngineCookies / EngineServer / EngineAPIResolverThe design goal is not “move everything to the client and optimize it later.” The compiler decides which parts actually require browser ownership first.
createPage() is the normal Gen 3 entrypoint
You do not need a separate Gen 3 page factory.
import { createPage, defineSchema } from "nextjs-engine";
const schema = defineSchema({
root: {
type: "section",
children: [
{ type: "heading", props: { content: "Hello" } },
],
},
});
export default createPage({
schema,
compiler: {
pageId: "home",
strict: true,
},
});For schemas without the legacy named-handler boundary, createPage() uses the Generation 3 compiler and server renderer by default.
Every returned page exposes its base compiler plan:
const Page = createPage({ schema });
console.log(Page.enginePlan.summary.clientIslands);The temporary migration escape hatch remains available when an older page still needs the v2 renderer:
createPage({
schema,
compiler: {
serverFirst: false,
},
});Named handlers currently keep the legacy provider path because that API still assumes one shared client-owned handler registry. Slots do not require that fallback; a server-owned page can pass an interactive React component through a slot and keep the surrounding schema on the server.
Runtime ownership
Typical ownership looks like this:
Schema work | Normal Gen 3 owner |
|---|---|
text, headings, boxes, grids, sections | server/static |
ordinary links | server |
animated Engine links | client island |
image markup | server with browser resource loading |
video | client island |
Canvas / Manim / Shader runtime | client island |
dialogs, drawers, popovers | client island |
interactive form controls | client island |
| server-owned boundary; slot content owns itself |
The compiler can upgrade an otherwise-static node when browser-only props, transitions, model bindings, handlers, or other client behavior are attached.
Adaptive phone and tablet compilation
Use normal responsive props for ordinary layout differences. They compile to CSS and do not require request-time device branching.
Use adaptive compilation when the actual schema structure should change by device class:
createPage({
schema,
mobile: "auto",
tablet: "auto",
});Phone and tablet compilation can compact structure and spacing while preserving intended visual quality. It does not silently reduce image quality, Canvas DPR, shader resolution, or geometry detail.
Shared runtime
EngineScheduler
One scheduler coordinates useful work across lazy mounts, images, video, Canvas/Shader monitoring, and near-viewport preparation.
Its six work states are:
critical → visible → near → deferred → idle → sleepingFrame pressure delays speculative work. It does not lower resolution by default.
In development, /_engine/debug exposes the scheduler's live task states and bounded transition history beside the page preview. The same workbench can pick compiler nodes, overlay STATIC, SERVER, CLIENT, and DEFERRED boundaries, and simulate viewport/device capability profiles. Its generated route is removed before production route discovery.
EngineViewport
EngineViewport is the shared browser viewport source. It tracks layout and visual viewport dimensions, offsets, orientation, scale, and keyboard inset behind one subscription surface.
const viewport = useEngineViewport();Use it when behavior genuinely depends on live viewport state. Prefer responsive schema/CSS for styling-only differences.
EngineModel
EngineModel provides shared observable state for Engine-owned browser behavior without forcing unrelated server-rendered schema into one page-level client boundary.
Compatibility and fallbacks
Every compiler plan includes a used-feature manifest and fallback plan.
Compatibility is evaluated only for features the page actually uses. A page that never requests WebGL, camera, speech, or View Transitions does not receive warnings about them.
Current built-in fallback chains include:
- View Transitions → Web Animations → instant navigation;
- IntersectionObserver → eager rendering;
- container queries → media-query layout → normal flow;
- VisualViewport → layout viewport;
- CSS Grid → normal flow.
Advanced graphics features remain native-only unless an application provides an explicit fallback policy.
Render the compiled result as an honest, hydration-safe browser warning with EngineCompatibilityDialog:
<EngineCompatibilityDialog plan={enginePlan.fallbackPlan} />It checks only used features, auto-opens only for fallback or unavailable results, and renders nothing when every used feature is native. Custom capabilities can provide explicit boolean support overrides; unknown capabilities otherwise fail closed.
Network and credential boundary
Browser-safe networking lives at:
import { EngineCommand, EngineCookies } from "nextjs-engine/network";Server-only request/security helpers live at:
import { EngineServer, createNENCDispatcher } from "nextjs-engine/server";NENC compiles logical commands into build-specific opaque wire identifiers and routes them through one /_static/command endpoint. Opaque ids are transport obfuscation, not authorization credentials.
For private operations, combine NENC with real authentication/authorization, replay protection, rate policy, origin checks, and device proof when appropriate. EngineCookieVault can keep credential material sealed with AES-256-GCM and release plaintext only inside controlled server operations.
Build integration
The combined Engine build plugin can compose the pieces that are actually configured by the application:
const { withEngine } = require("./src/engine/plugins/enginePlugin");
module.exports = withEngine(nextConfig, {
api: { /* EngineAPI / APIStatic options */ },
shader: { /* EngineShader options */ },
nenc: { /* optional NENC build options */ },
seo: { /* optional EngineSEO schema and generated crawler routes */ },
});Do not enable NENC, Shader compilation, or other subsystems merely because they exist. Configure the features the application actually uses.
Read next
Goal | Document |
|---|---|
Compiler, server rendering, scheduler, adaptive layout | |
NENC, EngineCookies, device proof, sessions, private backends | |
Used-feature manifests, fallbacks, legacy durability | |
Metadata, sitemap, robots, JSON-LD, and social previews | |
End-to-end device-bound private-search example | |
Schema/style/component APIs | |
Historical release contracts |
Current migration rule
New Generation 3 pages should start with normal createPage() and server-first compilation. Keep client ownership narrow and intentional. Use compatibility paths only where an older API still requires them, and remove those fallbacks when the real dependency is migrated.