Answer the Question First
For a Nuxt 3 project that must keep existing passport‑js and body‑parser middleware without rewriting, the most balanced approach is to use Nitro’s native server and wrap the legacy middleware as Nitro handlers. This preserves the middleware functionality, keeps the bundle lean, and still supports edge deployments. Only if the middleware relies heavily on Express‑specific globals or complex router nesting should a full Express integration be retained.
Why Nitro With Wrappers Wins
- Zero‑config, undici‑based runtime gives faster cold starts and native edge support (Vercel, Cloudflare).
- Middleware can be adapted with
defineNitroEventHandler by forwarding req and res objects; no additional runtime is added.
- Bundle size stays minimal – the Express binary isn’t bundled, only the lightweight wrapper code.
- Maintainability is higher: one framework to update, one CI pipeline, and fewer attack surfaces.
When Express Integration Is Still Needed
- Middleware uses global state like
app.locals or prototype modifications that Nitro can’t emulate.
- Complex nested routers (
app.use('/api', router)) that would require extensive rewiring.
- Existing unit tests or CI scripts are tightly coupled to Express internals.
Concrete Steps for the Wrapper Path
- Audit Middleware: List each middleware file and note any Express‑only APIs (e.g.,
app.use, req.app, res.locals).
- Create Nitro Handlers:
import { defineNitroEventHandler } from 'nitropack';
import passport from 'passport';
export default defineNitroEventHandler((event) => {
const { req, res } = event.node;
return passport.initialize()(req, res, () => event.node.res.end());
});
- Register in
nitro.config.ts:
export default defineNitroConfig({
serverMiddleware: [
{ route: '/api/auth', handler: '~/middleware/passport.js' },
{ route: '/api/body', handler: '~/middleware/body-parser.js' },
],
});
- Test Locally: Run
npm run dev with --nitro:debug to confirm middleware execution order.
- Benchmark: Use
wrk or autocannon to compare cold‑start latency against a pure Express setup.
- Deploy to Edge: Build with
nuxt build and deploy to Vercel or Cloudflare; verify that the middleware still sets cookies and parses bodies correctly.
- Monitor: Add simple logging inside the handlers to ensure they run on every request path.
What to Ask Before Finalizing
Does the legacy middleware use any Express‑specific globals (e.g., app.locals, req.app) or rely on prototype modifications that Nitro cannot emulate? If so, a dedicated Express micro‑service might still be the safer route.
Summary
Wrap the existing middleware in Nitro handlers to keep functionality, reduce bundle size, and maintain edge compatibility. Reserve a full Express integration only when the middleware’s Express‑centric features cannot be ported.