Hono vs Fastify vs Express for lean TypeScript APIs
Hono vs Fastify vs Express: compare middleware control, TypeScript friction, and production fit so you can pick the right stack for a small API.

Why this choice feels harder than it should
Hono, Fastify, and Express can all ship a small API. That is what makes the choice annoying. You are not removing bad options. You are picking the trade off that will bother you least six weeks from now.
Most small backends need a few plain things before they need raw speed: routes people can read without guessing, auth and validation that stay consistent, logs and errors that help during production issues, and a setup one or two developers can keep in their heads.
Each framework pushes you toward a different way of working. Express gives you a familiar, loose style. Fastify asks for more structure and usually pays that back later. Hono feels light and modern, which many teams like, but that same lightness can feel too bare if the team expects more built in guidance.
Benchmark charts rarely settle the argument. They test clean requests on clean code. Real APIs spend time waiting on database calls, outside services, retries, parsing, validation, and awkward business rules. In that world, a framework that saves one millisecond matters less than a framework that makes mistakes obvious.
Team habit changes the outcome more than most comparison posts admit. A founder with one full stack developer often asks, "Which one wins online?" The more useful question is, "Which one fits how we already build, test, and debug?"
If a team already thinks in Express style middleware, Express may feel faster to ship even with rougher typing. If the team likes stricter patterns and wants the framework to push them toward cleaner code, Fastify often feels easier after the first week. If the team likes the Web Request and Response model and wants a very small tool, Hono can feel natural right away.
That is why this choice keeps feeling harder than it should. There is no perfect winner. What matters is daily fit. Small backend projects usually go well when the framework matches the team's habits, patience, and tolerance for friction.
How the three frameworks differ at a glance
Express, Fastify, and Hono can all run a small API well. The real difference is how much structure they give you, how much they expect from you, and how quickly a small team can settle into a steady way of working.
Express keeps the core simple. You get routing, middleware, and a huge ecosystem, then you make most of the style decisions yourself. That freedom feels nice on day one. By month three, it can turn into a pile of local conventions unless someone keeps things tidy.
Fastify takes the opposite path. It pushes you toward plugins, schemas, and a more organized app shape from the start. That usually means more setup early on, but it also means fewer random patterns later. If your team likes clear boundaries and wants predictable behavior in production, Fastify often feels calmer than Express.
Hono stays small and close to web standards. Its request and response handling feel familiar if you already like the Fetch API. That makes it easy to read and keeps the mental load low. For a TypeScript API, Hono often feels lighter than both Express and Fastify, especially when you want a thin layer over standard web primitives instead of a framework with a strong personality.
The short version is simple. Express lets your team choose patterns and enforce them. Fastify asks your team to accept more structure up front. Hono asks your team to stay comfortable with a smaller ecosystem.
That last part matters. Express has the broadest library support and the most examples. Fastify has a strong plugin model and is usually easy to run in production without feeling heavy. Hono has grown fast because it feels modern and lean, but some teams will still find fewer ready made examples for odd edge cases.
For a team of two or three, the trade off is pretty clear. Express is easiest to start, Fastify is easiest to keep organized, and Hono is easiest to keep small. The better choice depends less on raw features and more on how much structure your team wants every day.
Middleware control in day to day work
Middleware feels different in these three frameworks because they push you toward different habits. Express treats middleware as the main path for almost everything. Fastify gives you hooks and plugins, so request flow feels more structured. Hono keeps the chain small and direct, which many teams like for a small API.
Express is the easiest to read at first. You add app level middleware, then route middleware, then the handler. Auth, request logging, body checks, and error handling all fit this model. The catch is order. Put one function in the wrong spot and a route can skip auth, log the wrong thing, or never reach your error handler.
Fastify feels stricter, and that usually helps once the app grows past a few files. You can still add middleware, but hooks often feel cleaner because they match clear stages in the request life cycle. preHandler makes sense for auth. onRequest works well for logging and tracing. Errors also stay more predictable because Fastify has a defined way to send and shape replies.
Hono is pleasant when you want route level control without much ceremony. Middleware wraps handlers in a simple chain, so auth and logging stay close to the routes that need them. If you already like the fetch Request and Response style, Hono feels natural fast. The awkward part shows up when you stack many wrappers and each one tweaks context in a slightly different way. Debugging still works, but you need discipline.
Once middleware stacks get deep, the trade offs are easier to see. Express gets harder to reason about because execution order does so much hidden work. Fastify stays organized longer because plugins and hooks give each concern a place. Hono stays compact, but too many context helpers can make route flow harder to follow.
For day to day work, auth, logging, and errors are easiest when the framework makes the path obvious. Express gives freedom, which is nice until the app gets messy. Fastify asks for more structure and usually pays that back. Hono keeps things light and quick to edit, which works well for small services, internal APIs, and startup tools where a team wants control without a lot of framework weight.
Where TypeScript friction shows up
If your route is /users/:id?active=true and the body carries { "role": "admin" }, the hard part is rarely the handler itself. The friction starts when you try to keep params, query, body, and middleware data typed the same way across the whole request.
Express usually asks for the most manual work. You can type Request, but query types often get awkward, body types depend on what you attach, and custom fields on req push you into declaration merging or type casts. That is fine for a tiny app. It gets old when you do it on every route.
Fastify feels stricter from the start. You can define Params, Querystring, and Body per route, and the editor usually follows along well. The trade off is noise. A small route can end up wrapped in enough generic types that simple code looks heavier than it is.
Hono sits in a lighter middle ground. Route params feel easy, and the request API stays clean. If you add schema validation with Zod or a similar layer, type inference saves real time because the same schema can drive validation and editor hints. Without that schema layer, body typing falls back to the same manual habits you would use elsewhere.
Where schema inference helps
Schema inference matters most when your API changes often. Fastify is strong here because schemas sit close to route definitions, so types stay near the code that uses them. Hono can feel just as smooth when you pair it with the right validator.
Express does not fight schema libraries, but it does not pull them into the framework very deeply either. You often validate in one place, type the request in another place, and hope both stay in sync.
Context extension is another spot where things can get messy. In Express, teams often add req.user, req.org, or req.traceId, then spend time teaching TypeScript that those fields exist. Fastify handles this more cleanly with plugins and decorators, but plugin types can spread through the codebase. Hono keeps context small, yet shared variables can become hard to track if you keep extending c across many middleware steps.
Editor hints tell the story fast. Fastify usually gives the sharpest hints once you set types up properly. Hono feels lighter and easier to read. Express often feels friendly at first, but its hints can be too loose, so mistakes survive until runtime.
For a small backend, the least annoying setup is usually the one that keeps request shapes obvious without making every route look like a TypeScript exercise.
Production fit for a small backend
Production fit comes down to boring things: start time, memory use, local dev speed, and how messy the code feels after a few months. For a small backend, those details matter more than benchmark charts.
Hono feels the lightest. It starts quickly, keeps memory use low, and leaves very little framework weight around your code. That is useful if the API is small, traffic is uneven, or you may deploy to edge runtimes later. Fastify is also lean on Node and usually stays efficient under real traffic. Express is usually fine for a tiny service, but it gives you fewer guardrails, so the result depends more on which middleware you stack on top.
Local work is often where teams feel the difference first. Express is easy to open and change, especially if the team already knows it. Fastify asks for a bit more structure early, but that structure can save time once routes, validation, and logging start to spread across the app. Hono also feels fast in daily work because its API is small and easy to keep in your head.
The pattern is fairly clear. Express works best when the service will stay on Node and you want the shortest path to shipping. Fastify fits best when you want Node performance plus a stronger app structure. Hono makes the most sense when Node is only one option and edge deployment may matter later.
Plugin depth is where small app simplicity can turn into friction. Fastify has a deeper plugin model, and that helps when a small API grows into auth, webhooks, jobs, and admin routes. Express stays simple at first, but six months later two developers may have solved the same problem in different ways. Hono stays pleasant when the service remains thin. If the app needs lots of older Node middleware, file handling, or very specific server hooks, Express and Fastify usually feel more natural.
A small startup admin API shows the trade off well. Express gets version one out fast. Fastify often feels cleaner by month six. Hono is a strong pick when you want the smallest surface area and the freedom to run beyond a standard Node server.
If I expected one maintainer, a few endpoints, and normal Node hosting, I would lean Fastify. If I wanted edge support or the lightest possible runtime, I would lean Hono. Express still makes sense when the team knows it well and wants to ship with very little ceremony.
A simple example: startup admin API
Picture a small admin API for a startup. Two people use it at first: a founder and an operations manager. They need to sign in, review customers, change account status, and check who changed what.
The first version usually needs a login route, request validation for forms and updates, logging for each admin action, and CRUD routes for users, plans, or support notes.
This is where the choice gets easier to judge. You are not picking a framework for a giant platform. You are picking one for a backend that should stay neat after the tenth new route, not just the first.
For the first version, Hono is often the tidiest. Route files stay short, middleware is easy to place, and the code reads cleanly. If you want to get an internal tool running this week, Hono feels light without feeling flimsy.
Express still works, and many teams move fastest with it because they already know it. The catch is discipline. Login, validation, and logging can spread across helpers and custom middleware quickly. A simple API can get messy once each route solves the same problem in a slightly different way.
Fastify usually asks for a bit more structure up front. That is not always fun on day one, but it pays off early. Validation, route schemas, and logging fit together in a more organized way, so the codebase stays calmer when a small backend starts acting like a real product.
Say the startup adds role based access, audit history, bulk updates, and stricter input rules after three months. Hono can still handle that well, but you will start making more architecture choices yourself. Express can handle it too, though teams often end up patching the same rough edges again and again.
Fastify is the one I trust most when requirements grow. It gives you enough structure to avoid drift without turning a small backend into a project full of ceremony.
If the admin API is truly small and speed matters most, Hono is a smart pick. If you expect the panel to grow into a serious internal system, Fastify is usually the safer bet. Express makes sense when the team already has strong habits and wants familiarity more than guardrails.
How to choose step by step
Start with the limits, not the framework. A small backend gets easier to maintain when you decide where it will run, how it will validate input, and who will fix bugs at 2 a.m. The debate gets much simpler once those limits are on paper.
-
Start with runtime and hosting. If you want edge runtimes, web standard APIs, or very small deploys, Hono often fits faster. If you know you will run a classic Node server with a longer process life and richer server features, Fastify usually feels more natural. Express is fine on plain Node, but it gives you less guidance.
-
Count the plugins you truly need. Not the dream list, the real one. If your backend needs logging, auth hooks, validation, docs, and a few common integrations, Fastify has a strong case. If your app is just a handful of routes plus one database and one auth layer, Hono can keep things cleaner.
-
Pick your validation style before you write routes. This choice affects almost every file. If your team wants a guided pattern with tighter structure, Fastify helps. If your team prefers small handlers and bringing its own tools, Hono stays out of the way. Express can do both, but you will assemble more parts yourself.
-
Choose the framework your team can debug calmly. That matters more than benchmarks for most small services. A two person startup team that already knows Express may ship faster with it today, even if Hono or Fastify looks nicer on paper. But if the team keeps fighting types, plugins, or middleware order, the "safe" choice stops being safe.
One simple rule works well: pick Hono for very lean APIs, Fastify for small backends that may grow into a more structured service, and Express only when team familiarity clearly beats the typing trade off.
Mistakes that waste time
Teams often lose more time on surrounding decisions than on the framework itself. A small API with 10 or 20 routes rarely breaks because one framework won a benchmark. It gets messy because the code stops following one clear pattern.
The first trap is chasing speed charts for a tiny service. For most small backends, database calls, auth checks, and outside APIs take more time than the router. If one request spends 40 ms in PostgreSQL, saving 1 ms in framework overhead will not fix much.
Another slow burn is mixing validation styles across routes. One handler checks fields by hand, another uses a schema, and a third trusts TypeScript types that disappear at runtime. That works for a week. Later, error messages differ, edge cases slip through, and nobody remembers which route follows which rule.
Typing can waste time too when the API shape still changes every few days. Teams often build neat generic helpers, shared wrappers, and deep request types before they know what the endpoints will look like in a month. Then a simple product change turns into a long cleanup job. Keep types close to each route at first. Pull them into shared helpers only after the same pattern repeats enough times.
Deployment limits also show up later than they should. A framework can feel perfect on a laptop and become annoying on the target host because of cold starts, memory limits, logging needs, or missing runtime support. That matters more than people expect. A tiny internal admin API has different needs than a busy public service, so test where it will actually run.
A few habits save hours later: measure a real route, not a toy benchmark; pick one validation approach and use it everywhere; keep early types plain while request shapes still move; and run the app on the target host before you commit.
This is where many small teams lose a week they did not need to lose. Consistency beats clever setup almost every time.
Quick checks before you commit
A framework can look fine in a demo and still become annoying once real work starts. Before you settle the choice, build one small protected route and inspect it line by line.
A good test is a route like POST /admin/users: it needs auth, input validation, one database call, and one clear error path. That single route reveals most of the pain you will feel later.
Ask a new developer to trace the request from the entry file to the final handler. If they need to jump across too many plugins, wrappers, or magic helpers, the code will age badly.
Read the auth and validation code out loud. If the happy path hides behind setup code, or the route logic disappears inside decorators and hooks, daily changes will feel slow.
Check your runtime first, not last. Hono is often the easiest fit if you may run on edge platforms or mix runtimes. Fastify feels most natural on Node. Express still works, but it gives you less help and more manual glue in TypeScript projects.
Remove one library in your test route and replace it with another. If that simple swap touches every handler, the framework and your app are too tightly mixed.
Try the boring maintenance test
Come back to the test route the next day and change one rule. Add a required field, tighten auth, or change the error format. Count how many files you touch.
That number matters more than benchmark charts for a small backend. Small teams do not suffer from losing a few milliseconds. They suffer when simple edits spread across six files and break type checks in two more.
If the route stays readable, your runtime supports it cleanly, and your libraries sit behind thin boundaries, you probably have a sound TypeScript backend choice.
What to do next
Do not pick a framework from benchmarks or GitHub stars alone. Build one real endpoint first. Use something your backend will actually need, such as creating a customer record, uploading a file, or handling a webhook with retries.
That small test tells you more than a long feature chart. You will see where the code feels clean, where types get annoying, and how much setup your team will tolerate on a normal week.
A useful trial includes auth for one protected route, request validation with clear error messages, structured logging you can read in production, and one deploy to the environment you plan to use.
If a framework feels nice only before you add these parts, take that as a warning. Small backends stay small for about five minutes. Once real users show up, weak error handling, awkward middleware, and messy types start to cost time.
Pay close attention to failure cases. Send bad input. Force a timeout. Return a database error. Check how easy it is to keep responses consistent. Then deploy it and notice the boring stuff: build steps, environment setup, startup time, and logging output. Those details usually matter more than a clever router API.
If your team is small, be honest about maintenance. Express still works, but you may spend more effort shaping it into a strict TypeScript setup. Fastify often feels more complete for production work. Hono can be a very good fit when you want a lean codebase and tight control, especially if you like a simpler mental model.
If the choice still feels close, an outside review can help. Oleg Sotnikov at oleg.is works with founders and small teams on startup architecture, backend decisions, and Fractional CTO work. A short consultation can save weeks of rewriting if you are about to lock in a stack too early.
Pick one endpoint, test the rough edges, and choose the framework your team will still like after the first on call issue.
Frequently Asked Questions
Which one should I pick for a small TypeScript API?
For most small TypeScript backends, Fastify is the safest default. It gives you enough structure for validation, logging, and route organization without feeling too heavy. Pick Hono if you want the smallest setup or may run on edge runtimes later. Pick Express when your team already knows it well and wants familiarity more than stricter typing.
Does Fastify speed matter for a small backend?
Not usually. On a small API, database calls, auth checks, retries, and outside services take more time than the router. A framework that keeps validation, errors, and logs easy to manage will save more time than a small win in raw request speed.
Which framework has the least TypeScript pain?
Express tends to create the most TypeScript friction. Params, query values, request body types, and custom fields on req often need manual work. Fastify gives sharper editor hints once you set route types up. Hono feels lighter, especially if you pair it with schema validation.
Is Hono better if I might deploy to the edge?
Hono usually fits edge runtimes best because it stays close to the standard Request and Response model. That makes it easier to move beyond a classic Node server later. Fastify feels more natural when you know you will stay on Node.
Which one handles middleware best as routes grow?
Fastify often handles auth, logging, and error flow more cleanly as the app grows. Its hooks and plugin model give each concern a clearer place. Express can work well too, but middleware order gets harder to reason about. Hono stays simple, though deep context changes can get messy if you overdo them.
Does Express still win on ecosystem and docs?
Express still has the widest ecosystem and the most examples. That helps when you need older middleware or hit an odd case. Fastify has a solid plugin system for production work. Hono has grown fast, but you may find fewer ready-made examples for unusual needs.
What is the best way to handle validation in these frameworks?
Use one schema-based approach across every route. That keeps runtime checks and editor types closer together. Fastify works well with this style out of the box. Hono also feels smooth with Zod or a similar validator. Express can do it, but you usually glue more parts together yourself.
Can I move from Express to Hono or Fastify later?
Yes, if the service is still small and your routes stay simple. Move one real endpoint first, including auth, validation, logging, and one database call. That test will show whether your current Express patterns map cleanly to Hono or Fastify before you rewrite the whole API.
What makes sense for a founder with one developer?
A solo founder or a two-person team often does well with Hono or Fastify. Hono helps when you want very little framework weight and fast setup. Fastify helps when you expect the admin API to grow and want cleaner boundaries from the start. Express still works if it is already second nature to you.
How can I test the choice before I commit?
Build one protected route before you commit. Include auth, validation, one database call, one error path, and a deploy to your real host. Then change one rule the next day and count how many files you touch. If simple edits spread too far, that framework or your app structure will get annoying fast.