PRNext 0.1.20: less work, more control

PRNext 0.1.20-alpha is available. This version addresses two costs that grow with an application: work performed unnecessarily and the difficulty of understanding production behavior. A public page can start with its native shell, a Server Action edit can spare unrelated tabs, and compiler caches have a shared retention budget.

The release also strengthens deployment controls with an explicit HTTPS origin, health checks that reject redirects, rollback after a traffic switch and protected metrics. New experimental paths remain disabled by default. Each serves a specific use case with defined activation conditions, fallbacks or explicit errors.

Start a PPR page before Node initializes

A PPR page combines a part prepared during the build with a React continuation that produces dynamic content. With experimental.nativePprShell, the Rust server can send the certified shell before starting the Node worker. The continuation then resumes from the same checked artifact instead of constructing an independent initial response.

This path covers concrete App Router PPR document GETs without cookies, authorization or query strings. It requires cacheComponents. Requests involving middleware, rewrites, basePath, CSP nonces or Flight navigation headers retain ordinary rendering. Generic parameter shells, Edge and external caches also remain outside this scope.

prnext.config.mjs
export default {
  cacheComponents: true,
  experimental: {
    nativePprShell: true
  }
};

The shell must be intact and unexpired. Any persisted invalidation disables this build snapshot optimization, including across restarts, without disabling PPR. A request already using a snapshot finishes with that same artifact. Responses remain private and no-store: this mechanism neither turns authenticated pages into public content nor replaces authorization.

Refresh the routes affected by a Server Action

Editing an action used by a billing screen need not interrupt a tab open in an unrelated part of the product. PRNext compares dependency graphs before and after the edit to identify routes that import the action directly or through its dependencies.

When that scope is established, the development refresh can target the affected routes. A spared tab applies its deferred generation before navigating to a changed route. Server generations still publish as a whole, and a pending mutation is never submitted again to accompany a refresh.

An unknown or incomplete graph retains a global refresh. Configuration, route, runtime and binding changes do too, alongside middleware, rewrites and certain internationalized, parallel or intercepting routes. Targeting depends on established scope rather than an assumption about the file you just saved.

Choose Oxc for React Compiler without making every project install it

React Compiler gains an experimental Oxc backend alongside the existing Babel backend. Browser output and App Client Component server rendering use separate transforms. Cache identities include the backend, compiler version and client or SSR mode so that a result cannot be reused in the wrong context.

Babel remains the default when reactCompiler is enabled. To select Oxc, explicitly install oxc-transform-react@0.157.0 in the application project with its optional native dependencies enabled. Even a global CLI resolves this compiler from the application. A missing or incompatible compiler or native binding produces an explicit error; PRNext never silently changes backends.

prnext.config.mjs
export default {
  reactCompiler: {
    backend: 'oxc'
  }
};

The scope remains eligible project components and hooks. Server Components, Server Actions, npm packages and the Pages server graph stay outside this transform. Source maps and Fast Refresh are preserved. The prnext compiler report identifies the backend and file-level diagnostics; the Oxc API does not provide the events needed to count optimized functions as Babel does.

Projects that retain Babel or disable React Compiler no longer install Oxc for PRNext’s internal use. Selecting a compiler written in Rust is not a measured speedup for your application: compare compilation, hydration and interactions with your own code.

Emit independent styles in parallel

experimental.parallelBuilds targets a specific App Router build stage. After ordered dependency discovery, PRNext freezes stylesheet plans, deduplicates outputs and distributes independent jobs. Linking remains deterministic to preserve stylesheet order.

Concurrency depends on CPU count, available memory and configured ceilings. This example allows at most two workers with an estimated admission budget of 512 MiB. The budget is not an enforced RSS limit on third-party code.

prnext.config.mjs
export default {
  experimental: {
    parallelBuilds: {
      maxWorkers: 2,
      maxMemoryMb: 512
    }
  }
};

Custom webpack hooks, loaders and PostCSS pipelines, as well as Sass callbacks, retain serial execution. If a job fails, PRNext stops new admissions, settles already started work and discards the staging build. The last published build remains available. The manifest records actual stylesheet job count and selected concurrency, distinguishing an enabled option from parallel work actually performed.

Read an upload before it finishes arriving

With experimental.streamingRequestBodies, a Node App Router Route Handler can begin reading Request.body before the entire upload arrives. Native transport negotiates this capability with the worker and sends at most one 64 KiB frame per reader credit. The consumer controls delivery pace.

Workers without that capability use the existing buffered path. Server Actions, Pages APIs and requests already buffered by middleware also retain their previous behavior. The total request limit remains 32 MiB and existing admission reservations still apply. This option promises neither a general reduction in V8 heap usage nor increased memory admission concurrency.

prnext.config.mjs
export default {
  experimental: {
    streamingRequestBodies: true
  }
};

The handler may execute before truncation or an excessive upload is detected. Validate the complete input and authorization before committing a business effect. Cancellation or an early return closes that upload’s lane without replaying the mutation or sacrificing the healthy Node host. For a data import, parse progressively and commit the transaction once all conditions are satisfied.

Give compiler caches a budget

Compiler caches share a 256 MiB retention target per project, configurable through compilationCache.maxDiskSize. The policy runs after builds, including failed builds, and after a clean development shutdown. It bounds retention of eligible files; active workers, busy files or incomplete scans can defer reclamation.

prnext cache reports statistics for recognized files. Its dry-run mode previews pruning without deleting data. This example inspects caches, then simulates a 64 MiB target from an application using this version of PRNext.

Terminal
npx --no-install prnext cache --json
npx --no-install prnext cache --prune --dry-run --max-bytes 67108864 --json

Large JSON records use compression with decoded-size, key and checksum validation. Existing raw records remain readable; corrupt or incompatible entries become cache misses. Publication remains atomic and cache failure does not become a mandatory dependency of compilation.

Stop development before applying a prune. Runtime databases, data.sqlite3, page and image caches and invalidation history are excluded. This is a retention target rather than a hard disk quota. Eviction may slow a later build or require a font to be downloaded again.

Keep fewer dependencies and redundant artifacts

PRNext bundles Fontkit’s Node create() entry with provenance and dependency licenses. TTF, OTF/CFF, WOFF, WOFF2, TTC, DFONT and variable fonts remain covered without installing the full external Fontkit dependency tree for this use. The internal integration does not replace Fontkit imports made by your application.

A production build keeps one OpenGraph renderer when needed. Bounded compiled-graph analysis can omit it only when ImageResponse is certified unused. Edge, development, unknown external modules and computed loading retain conservative behavior. Names, licenses and relative WASM loading remain preserved.

Runtime space is reclaimed off the request path through small SQLite steps and bounded orphan-file maintenance. Active readers and publications are protected. Existing databases keep their format and no full VACUUM runs during a request. Build and development temporary directories also have ownership journals: only local owners verified as abandoned become eligible for reclamation, while backups needed for recovery remain intact.

For standalone deployments, deploy the complete standalone directory without also copying the ordinary build beside it. This avoids duplicating the artifacts the framework has just assembled.

Remove unnecessary passes in builds and the browser

App chunk imports are rewritten in memory before their first write. Parent-directory discovery is shared within a build, and bounded Oxc summaries reuse directive and export information without retaining large syntax trees. Transforms that need Babel keep their existing path.

In the browser, adopting a group of stylesheets builds a temporary index of existing links instead of scanning the document for each sheet. Rust routing borrows more ordinary paths and segments. Flight capture removes an intermediate copy only for internally owned buffers where ownership permits it, retaining defensive copies for external producers.

Flight compression probes become asynchronous with bounded concurrency. At saturation, responses use ordinary Flight. PPR preloads reuse native base64 decoding where available, retaining the browser fallback. These changes reduce identified operations; they do not independently measure HTTP latency or complete build duration.

Preserve HTTPS and separate accounts in client state

Behind a reverse proxy, reconstructing an HTTP URL can break a redirect, secure cookie or authentication callback. server.publicOrigin now defines the canonical external origin for request URLs and redirects. It takes precedence over forwarding headers.

server.trustedProxies limits the IP addresses or CIDR networks of proxies that connect directly to PRNext. Only an allowed TCP peer may supply forwarded protocol and host. This rule does not validate a complete client-IP chain. Replace the example domain and addresses with those of your deployment, then rebuild the artifact that saves these settings.

prnext.config.mjs
export default {
  server: {
    publicOrigin: 'https://example.com',
    trustedProxies: ['127.0.0.1', '::1']
  },
  navigationCache: {
    authCookies: [
      'session-cookie-name',
      '__Secure-session-cookie-name'
    ]
  }
};

Cookie names must match your authentication library, including its secure variants. With this policy, a changed or unknown identity requires a fresh document before retained layouts or pages are adopted. A freshly verified same-account identity can keep its draft. PPR previews wait for that check and wholly static models use a document request.

The boundary also protects account switching and history restoration. Test account A, sign out, then account B in the same tab: A’s old layout props and private draft must not appear for B. The application remains responsible for authorizing every protected server read and mutation.

Check an instance after switching traffic

A 302 redirect to a sign-in page does not establish application health. Probes now require complete, bounded HTTP 200 responses. The reserved native /_prnext/health endpoint confirms that the server can accept traffic and becomes unavailable as soon as graceful shutdown begins.

Native readiness certifies neither an on-demand Node worker nor a database. A dedicated anonymous, read-only application route can check the dependencies required to serve traffic. Configure it as health-path for a persistent application. Previously saved health paths remain unchanged: an old / path that redirects needs explicit replacement with that dedicated route.

After a successful traffic switch, the manager retains the previous instance during a monitoring window, 15 seconds by default. Three consecutive health failures or an unexpected replacement exit can trigger a return to the previous instance if it is still healthy. Already started responses drain, but no request or mutation is replayed. A code rollback does not undo a SQL write or a schema migration.

Understand failures and effects already committed

The SaaS reference demonstrates account-scoped transactional idempotency. If a write succeeds but its response is lost, an explicit retry with the same key produces only one write. The constraint and transaction belong to the application; the framework cannot infer that another submission is safe.

Qualification scenarios exercise PostgreSQL outage and recovery, concurrent claims of the same key, response loss after COMMIT, SQLite locking and SQLITE_FULL on a disposable database, and a real Redis crash and restart. They complement successful nominal workflows with situations where the business outcome must remain understandable.

HTTP metrics are optional and bearer-protected through PRNEXT_METRICS_TOKEN. They expose durations, active requests, outcomes, admission saturation and worker events with bounded labels. Keep scraping private. OTLP export losses, queue overflows and partial rejections have counters; Node diagnostics also use the prnext.telemetry channel to remain observable when the trace collector is unavailable.

Dependency monitoring checks npm, Cargo and embedded renderer and font components daily, alongside weekly updates and recorded provenance. A release-time audit remains a snapshot rather than a replacement for monitoring new security advisories.

What the measurements establish

The storage study predates the final candidate and uses Windows x64, Node 24.22.1, matching React 19.3.1 peers and the same public native executable. Fresh installed size falls from 159.05 to 141.98 MiB with 13 fewer packages. These figures do not measure the final 0.1.20-alpha archives and do not automatically transfer to another platform.

Across 28 builds of two small synthetic SSR corpora, paired warm medians reduce logical build bytes by 67.79% without OpenGraph and 26.61% with OpenGraph. Compiler-cache bytes fall by about 64.4%. Observed build-API wall time increases by 13.94 and 15.85 ms. These are logical files rather than allocated disk blocks and a storage tradeoff rather than a general speed improvement.

The SaaS campaign referenced in the technical notes runs for two hours on qualification source 2323dc55 under observed limits of two CPUs and 5 GiB. It performs 9,238 SQL writes and 11 worker rotations with 235 verified process and file-descriptor samples. Eleven read-only probes fail during induced rotations and remain recorded; no mutation is replayed. These observations retain their executed source and are not presented as a test of the final archives.

These results document mechanisms and controlled workloads. They establish neither a general HTTP latency gain nor a general memory reduction, absence of leaks or production SLA. The technical notes linked to this article retain the campaigns’ conditions and limitations.

Prepare a deployment with your actual application

With matching packages installed, prnext check --production --json examines deployment settings, artifact drift, authenticated state retention and experimental options. It provides diagnostics before switching traffic; it cannot replace the routes, forms and callbacks specific to your product.

Terminal
npm install @thomas.f/prnext@0.1.20-alpha react@19.3.1 react-dom@19.3.1 react-server-dom-webpack@19.3.1
npx --no-install prnext check --production --json
npx --no-install prnext typecheck
npx --no-install prnext build
npx --no-install prnext output --json

PRNext 0.1.20-alpha requires Node ^22.23.4, ^24.22.1 or >=26.12.1 with React, React DOM and react-server-dom-webpack aligned at 19.3.1. Keep optional native dependencies enabled and framework and native package versions identical. Explicit typechecking needs the application’s TypeScript installation and tsconfig. These requirements do not replace applying new security patches for each dependency.

After changing versions, rebuild and restart the application. For pstart, first stop the supervisor with pdown using the same PRNEXT_PM_HOME, then update and rebuild every enabled application sharing that supervisor before restarting it. prestart alone does not reload supervisor code. Retain the previous deployment and compatible database migrations to allow a return.

PRNext remains an alpha with partial Next.js compatibility. Enable experimental paths separately and test a representative workflow: cold loading, styles, navigation, account switching, interrupted uploads and a dependency outage. The associated upgrade guide details these checks and the boundaries of each option.

Sources and further reading

Back to the blog