Migrate from Next.js
bext natively serves Next.js applications. It replaces the Node.js runtime and next start with a Rust-native SSR engine, ISR cache, and HTTP server. Most Next.js apps migrate in under an hour with no code changes to your React components.
Feature Mapping
| Next.js Feature | bext Equivalent | Notes |
|---|---|---|
next start |
bext-server run |
Drop-in replacement. Auto-detects Next.js project. |
ISR (revalidate) |
bext ISR cache | Reads revalidate from page exports. bext.config.toml can override TTLs. |
API Routes (/pages/api/) |
bext routes | Served natively. No Node.js process required. |
App Router (/app/) |
Supported | Server Components, Server Actions, and streaming all work. |
next.config.js rewrites |
[[route_rules]] |
Translate rewrite rules to bext route rules (see below). |
next.config.js redirects |
[[route_rules]] |
Use action = "redirect" in route rules. |
next.config.js headers |
[[route_rules]] |
Set custom headers per route pattern. |
Middleware (middleware.ts) |
bext plugins | Port to a QuickJS or WASM plugin, or use the built-in middleware.ts annotation fallback (comment-based @bext-redirect / @bext-rewrite). Real JS middleware evaluation was removed with the WebKit/JSC backend. |
| Image Optimization | bext image | Built-in. No external loader required. Configure in [image]. |
next/image |
Works as-is | bext serves the /_next/image endpoint natively. |
| Static exports | bext-server run |
bext serves the out/ directory as static files. |
| Environment variables | bext.config.toml + env |
NEXT_PUBLIC_* vars work unchanged. Server-side vars passed through. |
What Changes
- Remove
next.config.js(or keep it fornext buildonly). Runtime behavior is now configured inbext.config.toml. - Add
bext.config.tomlto your project root. - Replace
next startwithbext-server runin your deployment scripts. - Remove the Node.js runtime from your production Docker image (optional but saves ~100MB).
What Stays the Same
- Your
pages/orapp/directory structure - All React components, hooks, and client-side code
- CSS Modules, Tailwind, styled-components
getStaticProps,getServerSideProps,generateStaticParams- Server Actions and Server Components
public/static assets directory
Step-by-Step Migration
1. Install bext
curl -fsSL https://bext.dev/install | sh
2. Build your Next.js app
# Build as usual — bext consumes the Next.js build output
next build
Or let bext handle the build:
bext-server build
3. Create bext.config.toml
[server]
listen = "0.0.0.0:3000"
static_dir = ".next/static"
[render]
bundle_path = ".next/server"
workers = 4
[cache.isr]
max_entries = 10_000
default_ttl_ms = 60_000
default_swr_ms = 3_600_000
4. Translate rewrites and redirects
next.config.js:
module.exports = {
async rewrites() {
return [
{ source: '/blog/:slug', destination: '/posts/:slug' },
];
},
async redirects() {
return [
{ source: '/old-path', destination: '/new-path', permanent: true },
];
},
};
bext.config.toml:
[[route_rules]]
pattern = "/blog/:slug"
rewrite = "/posts/:slug"
[[route_rules]]
pattern = "/old-path"
action = "redirect"
redirect = "/new-path"
redirect_status = 301
5. Translate custom headers
next.config.js:
module.exports = {
async headers() {
return [
{
source: '/api/:path*',
headers: [{ key: 'Cache-Control', value: 'no-store' }],
},
];
},
};
bext.config.toml:
[[route_rules]]
pattern = "/api/**"
render = "ssr"
headers = { "cache-control" = "no-store" }
6. Start bext
bext-server run
Visit http://localhost:3000 and verify your pages render correctly.
7. Run your test suite
Run your existing integration tests and E2E tests (Playwright, Cypress) against the bext server. The HTML output should be identical.
Common Gotchas
next/dynamic with ssr: false -- Works as expected. The component is skipped during SSR and rendered client-side. No changes needed.
Custom server.js -- If you have a custom Node.js server (server.js), you cannot use it with bext directly. Instead, move your custom server logic to bext plugins or use bext as a reverse proxy to your custom server:
[server]
upstream = "http://127.0.0.1:3001" # your custom server.js
next.config.js webpack customization -- Webpack config only affects next build, which still runs in Node.js. bext does not replace the build step, only the runtime. Your webpack customizations continue to work.
getServerSideProps with database calls -- These run inside the V8 isolate. If you use Node.js-specific APIs (e.g., fs, net), they will not be available. Use bext's upstream proxy mode or move data fetching to an API route.
Middleware NextResponse.rewrite() -- bext does not evaluate middleware.ts as live JavaScript. It scans the file for comment annotations (// @bext-redirect, // @bext-rewrite) and applies those static rules. Redirect/rewrite middleware ports cleanly to annotations or [[route_rules]]; middleware that needs real request-time logic should move to a bext plugin (QuickJS or WASM).
getServerSideProps and Server Components that call Node.js-specific APIs (fs, net, child_process) will fail inside the V8 isolate — those APIs are not available. Move such data fetching to an API route or use bext's upstream proxy mode to keep that logic in a separate Node.js process.
Run your existing Playwright or Cypress test suite against the bext server before changing DNS. The HTML output is designed to be identical to next start, so a passing E2E suite is strong evidence the migration is complete.
Related
- PRISM Rendering Pipeline — how bext's SSR engine works under the hood
- Next.js on-demand — on-demand ISR and cache invalidation for Next.js routes
- Caching — ISR cache, stale-while-revalidate, and tag-based invalidation
- Server Actions — how
"use server"functions are handled - Plugins — porting
middleware.tslogic to QuickJS or WASM plugins - Configuration Reference — full
bext.config.tomlschema
Links
- nextjs.org — official Next.js documentation