Mandu vs Next.js
An honest, agent-first comparison — file-system routing, type-safe APIs, runtime guard, and AI-editor workflows on Bun + React.
On this page
Mandu vs Next.js
TL;DR — Same
app/**/page.tsxmental model. Mandu adds runtime architecture Guard, contract-first APIs, and 100+ MCP tools so AI agents can drive your codebase end-to-end. Built on Bun, not Node.
When to pick which
| You need… | Pick |
|---|---|
| The largest plugin ecosystem and Vercel-first DX | Next.js |
| AI agents (Claude Code · Cursor · Codex · Copilot) writing most of the code without breaking architecture | Mandu |
| Bun-native performance + edge adapters out of the box | Mandu |
| To stay on Node and pull from npm's full long-tail | Next.js |
Side by side
| Feature | Next.js 16 | Mandu 0.46 |
|---|---|---|
| Routing | app/**/page.tsx, [lang], [...slug] |
app/**/page.tsx, [lang], [...slug] (same convention) |
| Runtime | Node.js (Edge for middleware) | Bun ≥ 1.3.12 (or embedded binary) |
| Architecture enforcement | ESLint plugins (lint-time only) | Runtime Guard — rejects layer/import violations as the dev server runs |
| API contracts | Hand-wired zod + manual TS types + manual OpenAPI | Mandu.contract({...}) → types, validation, OpenAPI auto-derived |
| AI agent surface | Plugin or chat-based assistance | 100+ MCP tools (route/contract/guard/ATE/decision-memory/deploy) |
| Test generation | Manual | ATE auto-generates contract tests, mutations, oracles |
| Decision memory (ADR) | None | Built-in — mandu_decision_save writes structured ADRs |
| Deploy targets | Vercel + community adapters | Vercel · CF Pages · Fly · Railway · Netlify · Docker · Docker Compose — mandu deploy --to=<target> generates platform config |
| Edge runtime adapters | Vercel Edge, Cloudflare (via OpenNext) | CF Workers · Vercel Edge · Deno Deploy · Netlify Edge — first-class |
| Type-safe client | Server Actions or hand-rolled fetch | client(contract) — typed wrapper auto-generated from the contract |
| i18n | App Router [lang] |
App Router [lang] + locale-variant docs (<slug>.ko.mdx) |
| Hydration unit | "use client" components | .island.tsx files (explicit boundary, easier for agents to reason about) |
Code comparison — typical signup endpoint
Next.js (~30 lines, hand-synced everywhere):
// app/api/signup/route.ts
import { z } from "zod";
import { NextRequest, NextResponse } from "next/server";
const SignupSchema = z.object({
email: z.string().email(),
password: z.string().min(8),
});
export async function POST(req: NextRequest) {
const csrf = req.headers.get("x-csrf-token");
if (csrf !== req.cookies.get("__csrf")?.value)
return NextResponse.json({ error: "csrf" }, { status: 403 });
const raw = await req.json().catch(() => null);
const parsed = SignupSchema.safeParse(raw);
if (!parsed.success)
return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 });
try {
const user = await db.user.create({ data: parsed.data });
return NextResponse.json({ id: user.id }, { status: 201 });
} catch (err) {
if ((err as any).code === "P2002")
return NextResponse.json({ error: "duplicate" }, { status: 409 });
return NextResponse.json({ error: "internal" }, { status: 500 });
}
}
Mandu (6 lines + a contract file, both type-checked together):
// app/api/signup/route.ts
import { Mandu } from "@mandujs/core";
import { SignupContract } from "@/spec/contracts/signup.contract";
export default Mandu.handler(SignupContract, {
POST: async (ctx) => ctx.created({ id: (await ctx.db.user.create({ data: ctx.body })).id }),
});
The contract file (spec/contracts/signup.contract.ts) is the single source of truth — Mandu derives request/response types, runtime validation, OpenAPI export, and a typed client wrapper from it. An agent only has to read the contract to know what the API does.
Migration path
If you're already on Next.js, you can move incrementally:
- Same routing tree — copy
app/over;page.tsx,layout.tsx,[lang],[...slug]work as-is. - Replace
route.tshandlers withMandu.filling()chains orMandu.handler(contract, ...)— the handler signature is the only meaningful diff. - Lift hand-wired auth to the chain (
.use(withSession()),.use(withCsrf())). - Add
mandu.config.tsand runmandu guardto surface any architectural violations in the existing code.
When Next.js is still the right call
- Heavy reliance on Vercel-specific Next features (ISR-by-tag, Server Actions ecosystem, partial pre-rendering) that Mandu has equivalents for but with smaller community footprint.
- Team has zero appetite for Bun runtime (the
@mandujs/clipackage keeps you on Node-style npm install at least, but the runtime itself is Bun). - Plugin you depend on only ships as a Next plugin.
🤖 Agent Prompt — explore Mandu against your existing Next code
I have a Next.js app and I'm evaluating Mandu (https://mandujs.com).
1. Pick a representative route (an API + a page) from my codebase.
2. Show me what the same route would look like as Mandu —
`Mandu.filling()` chain or `Mandu.contract({...})` +
`Mandu.handler(contract, ...)` — using the exact paths and types
my Next route already uses.
3. Highlight which lines disappear (CSRF, manual zod parse, status
code branching) because Mandu derives them from the contract.
4. Estimate how much of the codebase would migrate cleanly vs need
rewriting (give me a percentage with reasoning).
5. List the top 3 risks of switching for my project specifically.
Related
- start/quickstart — install Mandu in 5 minutes
- recipes/create-api — both Mandu API patterns
- architect/guard — what Guard catches at runtime
- migrate — full migration guides (Next, Remix, Astro, SvelteKit)
For Agents
Mandu replaces Next.js for projects where AI agents drive most of the code. Same file-system route convention (`app/**/page.tsx`) but Mandu adds runtime architecture guard, contract-first APIs (one zod schema → types + validation + OpenAPI), 100+ MCP tools for direct agent control, and Bun-native runtime. Use Next.js if you want maximum ecosystem; use Mandu if you want agent-safe code at scale.