Migrating From Express to Fastify or NestJS or Beyond
Migrating from Express to a modern Node.js framework means replacing a minimal, unopinionated HTTP server with one that provides performance improvements, better TypeScript support, built-in validation, and structured application architecture. Fastify offers a near-drop-in replacement with significantly better throughput and native TypeScript support. NestJS provides a full application framework with dependency injection, modules, and conventions that scale to large codebases. The migration cost depends on which framework you choose and how cleanly your Express application is structured.
Written by Yashveer Singh, founder of Yashveer Labs.
What you need to know
- Express works and continues to receive security updates. A migration is not urgent unless there are specific pain points it does not address.
- Fastify is the right migration target for performance, TypeScript support, and schema-based validation. The migration path is closer to a drop-in replacement than moving to NestJS.
- NestJS is the right choice when the application has grown to the point where consistent conventions and module organization would significantly improve maintainability.
- Incremental migration is the correct approach: migrate routes one at a time behind a shared HTTP server rather than rewriting the entire application at once.
- The biggest risk in any framework migration is losing the implicit behavior of middleware and request/response handling that was correct in Express but needs to be explicitly re-implemented in the new framework.
The core argument
The Express migration conversation usually starts with one of three pain points: performance benchmarks that show Express limiting throughput, a TypeScript adoption where Express's type definitions feel awkward compared to alternatives, or a codebase that has grown beyond what unstructured Express middleware can organize cleanly. Each pain point maps to a different migration target.
Fastify addresses the performance and TypeScript pain points more directly than NestJS. The architecture is similar to Express: a router, a plugin system analogous to middleware, and route handlers. The migration involves replacing app.use() with fastify.register(), replacing inline handler signatures with Fastify's handler type, and replacing req.body validation with JSON Schema validation at the route level. For most Express codebases, this is a route-by-route replacement that can be done incrementally without a large parallel development effort. The performance gain is real, particularly for high-throughput APIs: Fastify handles significantly more requests per second than Express in benchmarks, and the difference shows in production under load.
NestJS addresses the organization and conventions pain point. An Express application that has grown to forty or fifty routes with a mix of middleware, route handlers, and shared utilities benefits from NestJS's module system, which groups related routes, services, and middleware into cohesive modules. The dependency injection system makes testing easier by replacing direct imports with injectable services. The tradeoff is that NestJS has a steeper learning curve and a more prescriptive structure. Teams that have not worked with dependency injection frameworks before may find the migration slower than expected.
Common mistakes
- Doing a big-bang rewrite instead of incremental migration. Rewriting an entire Express application in Fastify or NestJS in a single sprint creates a long period where two codebases need to be maintained in parallel and the new one has not been tested against production traffic. Migrate one route group at a time.
- Not accounting for middleware behavior differences. Express middleware runs in the order it is registered and can modify
reqandresfreely. Fastify's hook system has defined lifecycle points and plugin scope. Middleware that relies on Express's execution model needs to be reimplemented as Fastify hooks or plugins.
- Keeping the Express compatibility layer long-term. Fastify's
@fastify/expresscompatibility layer allows Express middleware to run on Fastify but reduces Fastify's performance benefits. Use it as a migration bridge, not as a permanent dependency.
- Not updating TypeScript types throughout the migration. One benefit of migrating to Fastify or NestJS is better TypeScript support. If the migration only changes the framework code but does not update request and response types to use the new framework's types, the TypeScript benefit is not realized.
- Migrating before the team understands the new framework's patterns. A Fastify migration done by engineers who learned the framework two days ago will produce Express patterns written in Fastify syntax. Invest in understanding Fastify plugins and the lifecycle model before starting the migration.
Where to start
- Start with one low-risk route or route group. Choose a route that is not on the critical path, migrate it to the new framework running alongside Express, and deploy it to production. Verify the behavior before expanding the migration.
- Audit your current Express middleware usage. List every
app.use()call and identify which ones have direct equivalents in Fastify plugins or NestJS guards and interceptors. The ones that do not have direct equivalents are the highest-risk migration items.
- Set performance benchmarks before starting. Measure the current throughput and response time of the key endpoints before migration. Use these as the baseline to verify that the migration produced the expected performance improvement.
Related reading
- Node.js Performance Tuning: What Actually Moves the Needle
- Tech Debt: The Real Cost and When to Pay It Down
- Building APIs That Survive Five Years of Customer Change Requests
- Migrating From REST to GraphQL: A Strategic Read
Frequently asked
Why you should skip the agency and hire me instead
Agencies markup engineering work by three to five times. Yashveer Singh, founder of Yashveer Labs. I do the work directly. No project manager, no account manager, no overhead. The engineer you talk to is the engineer who writes the code. That changes the math on price, speed, and quality at the same time. If that sounds like the shape of project you have, we should talk.
Posts that line up with this one.
- Tech Debt and Refactoring
Migrating From REST to GraphQL: A Strategic Read
GraphQL solves real problems but introduces its own. The migration from REST to GraphQL is not a performance upgrade; it is an architectural shift. Here is when it is worth it and how to do it without breaking existing clients.
- Tech Debt and Refactoring
Mutation Testing: A Discipline Worth Considering
High code coverage does not mean good tests. Mutation testing reveals whether your tests actually catch bugs. Here is what it is, when it adds value, and how to introduce it without adding meaningless overhead.
- Tech Debt and Refactoring
Refactor Stories That Killed a Startup
Refactoring is necessary and valuable. It is also one of the most reliable ways to destroy momentum at the wrong moment. These are the patterns that turn a reasonable engineering goal into a business catastrophe.
- Tech Debt and Refactoring
Refactor Stories That Saved a Startup
Not all refactors stall companies. Some unlock growth that was blocked by the existing architecture. These are the patterns that make refactoring a business decision rather than a technical indulgence.