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
1. Remove next.config.js (or keep it for next build only). Runtime behavior is now configured in bext.config.toml.
2. Add bext.config.toml to your project root.
3. Replace next start with bext-server run in your deployment scripts.
4. Remove the Node.js runtime from your production Docker image (optional but saves ~100MB).
What Stays the Same
- Your pages/ or app/ 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 runs Next.js middleware in its V8 engine. Most middleware works unchanged, but middleware that uses Node.js APIs (crypto, Buffer) may need porting to Web-standard APIs (which bext's V8 supports).