Vapor vs Hummingbird in 2026: Choosing a Server-Side Swift Framework
You are starting a Swift backend. Maybe it is the API behind an iOS app, maybe a server-rendered site. You have narrowed it to two names, and what you typed into a search box was some version of vapor vs hummingbird. Both look fine. The forum threads that come up first were mostly written before either framework's current major version existed, and they argue about things that are no longer true.
Here is the state of play as of late September 2026, when this was written. Vapor 4 is the stable line, at 4.122.2, released on September 17. Vapor 5 is in public beta: Beta 1 shipped on September 15 and Beta 2 the day after. Hummingbird 2 is at 2.27.0, released on September 21. If you are reading this later, check them first.
Our argument is that the two are closer than the debates suggest. Both are built on SwiftNIO, both can use the same ORM, both work with the same HTML library, and both deploy the same way. The choice that matters sits on three other axes: how much you want decided for you, how far ahead you are planning given Vapor 5, and where the thing will run.
Vapor vs Hummingbird: the short answer
- Choose Vapor 4 if you want one dependency that already covers routing, sessions, validation, authentication helpers and WebSockets, and you value convention and a larger body of existing Vapor code.
- Choose Hummingbird 2 if you want a deliberately small core, prefer adding features one package at a time, and want a framework designed around structured concurrency rather than one migrating towards it.
- Lean Hummingbird if AWS Lambda is your main target and you want a first-party adapter. Vapor runs on Lambda too, through a community package.
- Choose either if the plan is Postgres through Fluent, HTML rendered with Elementary, and a Docker image on Linux. That stack works on both.
- Do not wait for Vapor 5 to decide. It has no committed release date, and Vapor 4 has a stated support window after it ships.
The same route in both
Start with a handler, because it says more about each design than a feature table does. This is Vapor 4's minimal route, as the current Vapor routing docs show it:
// Vapor 4
app.get("hello", "vapor") { req in
return "Hello, vapor!"
}And this is Hummingbird 2's, from the project README. It includes the lines that build and run the app, because in Hummingbird those are part of the point:
// Hummingbird 2
import Hummingbird
let router = Router().get { req, context in
return "Hello, Swift!"
}
let app = Application(router: router)
try await app.runService()A route on a named path looks the same way, with the unused context ignored:
router.get("hello") { request, _ -> String in
return "Hello"
}Two differences are worth reading closely. The first is the closure signature. Vapor hands your handler a single Request, and what you need hangs off it. Hummingbird hands you two things: the request and a context. The context is how Hummingbird carries per-request state without one large Application and Request object graph that every feature plugs into.
The second is who owns the lifecycle. The Hummingbird sample builds a Router, passes it to an Application and runs it from async code. Nothing is hidden. Vapor's route registration assumes an app that the framework's conventions have already configured and booted elsewhere. One gives you a frame to fill in; the other gives you parts to assemble.
Both samples are plain strings, copied from each project's own pages. For the JSON-returning version, take the exact spelling from the current docs rather than from an article.
Batteries included vs modular core
This is the real difference, and it is about packaging more than capability. The Vapor package brings routing, sessions, validation, WebSockets, authentication helpers and the hooks for templating in one dependency. Fluent and its database drivers are separate packages, but they live in the same GitHub organisation and are designed alongside it.
Hummingbird's core is minimal on purpose. Almost everything else is its own package under the hummingbird-project organisation:
- hummingbird-auth for authentication, covering bearer tokens and session-style auth.
- HummingbirdWebSocket for WebSockets.
- hummingbird-fluent to use Fluent.
- hummingbird-postgres, a lighter driver built directly on PostgresNIO's PostgresClient, for teams that do not want a full ORM.
- hummingbird-lambda for AWS Lambda.
- swift-jobs for background jobs, and swift-mustache for templates.
Fluent needs its own paragraph, because it is the piece people assume ties you to Vapor. It does not. Fluent is a Vapor project, but it was built to be usable outside Vapor, and hummingbird-fluent is the official way to use it from Hummingbird, with the same Postgres and SQLite drivers.
Testing follows the same split. Vapor 4 has two paths: XCTVapor, the long-standing XCTest helpers, and VaporTesting, for teams on Swift Testing with async/await. Hummingbird has HummingbirdTesting. Vapor's own testing story is mid-transition, since moving to Swift Testing is one of the phases on the Vapor 5 roadmap.
So what you are really choosing is who makes the second-order decisions. Vapor has an opinion about sessions, validation and auth, and you get those opinions whether you use them or not. With Hummingbird, you make each choice when you need the feature, and a service that never needs WebSockets never depends on them.
We made a version of the same argument about our own code: a dependency you cannot express is a mistake you cannot make.
Scaling Swift Projects With Modular Packages
Concurrency and Swift 6
Hummingbird 2 was, in its maintainers' words, a complete rewrite built on top of structured concurrency, refined over roughly 15 months. Most references to SwiftNIO's event loops were replaced with async/await. It compiles with strict concurrency checking set to complete, and core types such as Request are Sendable. The README badge said Swift 6.1+ when we checked on September 27, 2026.
Vapor 4 comes from an earlier generation of Swift. Its foundations are SwiftNIO's EventLoop and EventLoopFuture, and removing them is the headline of Vapor 5, which tells you how deep they run in 4.
Vapor 5 drops EventLoop and EventLoopFuture entirely in favour of async/await and what the team calls real structured concurrency. It adopts a new HTTP server built on Swift HTTP Server, with bidirectional streaming and HTTP/3 support, and ships an experimental macro library for type-safe routing and parameters and compiler-checked authentication. It also raises the floor sharply: Swift 6.4 or later, and macOS 26 or later.
Hummingbird 2 already has the design Vapor is moving to. Vapor users will get there too, by way of a migration. If strict concurrency in your own codebase matters to you today, that is a real point for Hummingbird. If it does not, it is a point about the future, which is the next section.
The Vapor 5 question
Vapor 5 is a rewrite, not a version bump. The roadmap the Vapor team published has eight phases: remove the future-based APIs, introduce a service architecture with dependency injection, resolve Sendable issues, ship the new HTTP server, integrate Swift Service Lifecycle, move to Swift Testing, rewrite the WebSocket and MultipartKit APIs, and add new approaches to routing and validation.
What the team has committed to: Vapor 4 goes into maintenance mode when 5 ships, with bug fixes and security patches for at least six months after that, and paid extended support planned. Vapor 5 itself is committed to at least three years of support. What they have not committed to is a date. In their words, they "don't have a complete timeline for the Vapor 5 release as some of it depends on the ecosystem dependencies."
If you are starting a project now, that translates into four rules:
- Do not block on it. An undated beta is not a reason to hold a project, and a support window that starts at an undated release is not something you can plan against yet.
- If you pick Vapor 4, keep EventLoopFuture out of your own APIs, and keep WebSocket and multipart handling behind a thin layer of your own. Those are areas the roadmap says will change.
- Check your toolchain floor. If your CI image, your deploy image or your team's Macs cannot move to Swift 6.4 and macOS 26 soon, Vapor 5 is further away for you than its release date.
- If avoiding a framework migration is what you care about most, that is a legitimate point for Hummingbird: its async-first rewrite has already happened.
Beta 2 was less than two weeks old when this was written, and nothing we found describes how production-tested the new HTTP server or the macros are yet. Try the beta on a branch. Do not deploy it.
Deployment: Docker, Linux, Lambda
Both frameworks build and run on Linux under Docker, and we found nothing suggesting a gap between them there. This site is deployed exactly that way: a multi-stage Docker build that compiles on the swift:6.0-jammy image and runs on plain Ubuntu Jammy, on Heroku.
That base image is also where the Vapor 5 floor stops being abstract. For us, moving to Vapor 5 means moving the build image from Swift 6.0 to 6.4 or later, and running the project locally on a Mac means macOS 26. Neither is hard. Both are work you schedule.
AWS Lambda is where the two genuinely differ. Both sit on the same runtime, swift-aws-lambda-runtime, which now lives in the AWS Labs organisation on GitHub. Hummingbird has a first-party adapter, hummingbird-lambda, maintained alongside the framework. Vapor's route is vapor-aws-lambda-runtime from vapor-community, which bridges API Gateway requests into Vapor's Request and Response. The difference is who you depend on to keep up when the framework or the runtime moves.
We have not measured cold starts for either, and the one figure we came across was a single blog's claim, so we are not repeating it. Cold start depends on binary size and on what you do at launch. Measure your own.
What we run and why
This site runs on Vapor 4. One binary serves four domains, with Fluent and the Postgres driver for the parts that need a database, and vapor-elementary for rendering HTML. The manifest, trimmed:
// Server/Package.swift (this site)
dependencies: [
.package(url: vaporURL, from: "4.99.0"),
.package(url: fluentURL, from: "4.0.0"),
.package(url: fluentPGURL, from: "2.0.0"),
.package(url: vaporElementaryURL,
from: "0.2.0"),
]The package floors are swift-tools-version 5.9 and macOS 14, which puts Vapor 5's Swift 6.4 and macOS 26 some distance away. That distance is a planned upgrade rather than an emergency, and the Vapor 4 maintenance commitment is what makes it one.
The more interesting part is Elementary. Swift.org's August 2026 roundup describes it as a modern HTML rendering library that "integrates easily with frameworks like Vapor and Hummingbird". The package holding every shared HTML component on our four sites depends on two Elementary packages and nothing else. It has no idea Vapor exists. If we ever changed framework, the rendering layer would not be the part that moved.
Swift.org: What's new in Swift, August 2026 Edition
We also work on both sides of the line. FeedbackKit, our own product, ships a Vapor SDK and a Hummingbird SDK next to its app and web SDKs, so a backend team can integrate it whichever framework they chose. That is why this article does not end with "use what we use".
Logging does not change with the framework at all: both use swift-log, so the server half of our logging guide applies to either.
Leveraging the Logger API in SwiftUI: A Developer's Guide
What this comparison cannot tell you
- Which one is faster. We found no published, reproducible benchmark comparing Vapor 4 and Hummingbird 2 with its hardware and method disclosed. Both are built on SwiftNIO, and relative performance will depend on your workload and configuration. If it matters, benchmark your own endpoints on your own hardware.
- How stable Vapor 5 is. The beta is new, and nothing public we found describes production use of it yet.
- Who funds either project. We found maintainer names but no primary source on organisational backing, so we are not ranking them on longevity.
- What a large Hummingbird service feels like after three years. We run Vapor in production and maintain a Hummingbird SDK. That is not the same thing.
How to decide in an afternoon
- Write down where the service will run. Lambda-first leans Hummingbird for the first-party adapter. Docker on Linux is neutral.
- Check your toolchain against Vapor 5's floor of Swift 6.4 and macOS 26. If you cannot get there soon, you will be on Vapor 4 for a while if you choose Vapor.
- List the features you need on day one: auth, sessions, WebSockets, background jobs, templating. A long list and a wish for one opinion on all of it leans Vapor. A short list leans Hummingbird's core plus a package or two.
- Build the same two endpoints in both: one that returns JSON, one that reads a row from Postgres through Fluent.
- Write one test for each, with XCTVapor or VaporTesting on one side and HummingbirdTesting on the other.
- Decide whether strict concurrency in your own code matters now or later. Now leans Hummingbird. Later is what Vapor 5 is for.
- Pick, and write the reason in your README. It will be one of the three axes above, not the forum thread.
Both are good frameworks. The mistake is rarely choosing the wrong one. It is choosing on the wrong grounds: a benchmark nobody can reproduce, or a Vapor 5 date nobody has promised.
If the backend you are planning exists mainly to sit between an app and several AI providers, the framework is the smaller of the decisions in front of you.
Comments
Loading comments…