Koa.js: A Minimal Async Middleware Framework for Node.js
Expressive middleware for node.js using ES2017 async functions
At a glance
- What is it?
- Koa is a Node.js HTTP framework built around ES2017 async functions and a stack-based middleware model. It ships no bundled middleware and provides a small core of around 570 lines of source code. Every capability beyond HTTP basics is added through separate packages.
- Who is it for?
- Koa suits Node.js developers who want precise control over their middleware stack and are comfortable selecting and wiring every component themselves. It is not the right choice for teams who need a batteries-included framework with built-in routing, templating, and body parsing: those need to be added explicitly.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 11 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The Problem Koa Addresses in Node.js HTTP
Writing HTTP servers in Node.js directly requires dealing with several inconsistencies in the built-in http module: stream handling, content negotiation, redirect logic, and the mismatch between how IncomingMessage and ServerResponse model requests and responses. Koa's README describes the framework as addressing normalization of node inconsistencies along with content negotiation and redirection, all in a codebase of approximately 570 source lines.
The key design decision separating Koa from its contemporaries is the middleware execution model. Koa's middleware stack runs in a cascade, meaning each middleware function can act before passing control downstream with await next(), then act again on the way back upstream after downstream middleware has finished. This gives each function two chances to operate on a request: once on the way in, once on the way out. The README describes this as flowing in a stack-like manner, allowing actions downstream and then filtering and manipulating the response upstream.
Koa requires Node.js 18 or higher for ES2015 features and native async function support.
Async Functions and the Middleware Cascade
Koa's middleware model relies on async functions. Each middleware receives a context object (ctx) and a next function. Calling await next() passes control to the next middleware in the stack. When that middleware resolves, execution returns to the calling middleware at the line after the await. This produces a natural before/after pattern within a single function.
The README provides a logger middleware as the canonical example:
app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});The start timestamp is captured before downstream middleware runs. After all downstream middleware completes and the response is being built, the elapsed time is logged. The same pattern applies to authentication checks, response transformation, and error handling. A middleware that needs to run both before and after the downstream chain can do both within one function, without callbacks or event emitters.
The README also documents the older promise-based common function signature for middleware that does not use async/await:
app.use((ctx, next) => {
const start = Date.now();
return next().then(() => {
const ms = Date.now() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
});As of version 3, the v1.x generator-based middleware signature has been removed entirely. The docs/migration-v2-to-v3.md file in the repository covers the upgrade path from v2.x to v3.x.
Installing Koa and Writing a First Server
Koa is distributed through npm. Install it with:
npm install koaThe README gives a minimal working server:
const Koa = require('koa');
const app = new Koa();
// response
app.use(ctx => {
ctx.body = 'Hello Koa';
});
app.listen(3000);Setting ctx.body to a string sends a 200 response with that string as the body. The application object created by new Koa() is Koa's interface with Node's HTTP server. It handles middleware registration, request dispatching, default error handling, and configuration of the context, request, and response objects.
The package is available as version 3.2.1 and supports both CommonJS (via lib/application.js) and ES module (via dist/koa.mjs) import styles, as shown in the exports field of the package.json. The build step generates the dist/koa.mjs file; the generate-config.sh and prepare scripts handle this at install time.
To run the test suite:
npm testThe Context Object: Request, Response, and Stream Handling
Koa wraps Node's IncomingMessage and ServerResponse in a single Context object, typically referenced as ctx. The Context exposes a Request object via ctx.request and a Response object via ctx.response. Many properties are available as shortcuts on ctx directly: ctx.type works as an alias for ctx.response.type, and ctx.accepts works as an alias for ctx.request.accepts.
The README gives this example of checking whether the client accepts XML before proceeding:
app.use(async (ctx, next) => {
ctx.assert(ctx.request.accepts('xml'), 406);
await next();
});ctx.assert is equivalent to writing if (!ctx.request.accepts('xml')) ctx.throw(406), which the README documents as the explicit alternative. Both approaches use the http-errors and http-assert packages that are bundled in Koa's dependency list.
The response body supports multiple types. Strings produce text responses. Buffers are sent as binary data. Readable streams are piped directly to the client. The README demonstrates the stream case:
app.use(async (ctx, next) => {
await next();
ctx.response.type = 'xml';
ctx.response.body = fs.createReadStream('really_large.xml');
});Koa's pattern of delegating to Node's request and response objects rather than extending them reduces conflicts between middleware. When direct access to the native objects is needed, ctx.req gives the raw IncomingMessage and ctx.res gives the raw ServerResponse. The Context API Reference is documented in docs/api/context.md inside the repository.
What the Core Bundles: koa-compose and the Dependency List
The package.json lists the packages Koa's core depends on directly. These reveal exactly what the framework handles versus what it leaves to the developer. The accepts, content-type, mime-types, type-is, and vary packages cover content negotiation, MIME type lookup, and Vary header management. The cookies package handles cookie parsing and setting. The fresh package handles HTTP conditional request checking based on ETag and Last-Modified headers. The http-assert and http-errors packages provide the ctx.assert and ctx.throw utilities. The parseurl package parses request URLs. The statuses package maps HTTP status codes to their text descriptions.
koa-compose, listed as a direct dependency, is the package that implements the middleware cascade itself. It takes an array of middleware functions and returns a single function that runs them in order with the async/await chain described above. The Koa application object registers middleware through app.use() and uses koa-compose to execute the stack for each request.
Notably absent from the dependency list: a router, a body parser, session management, a template engine, and multipart form handling. These are the areas where Express bundles defaults and Koa does not. Each must be added as a separate package and registered via app.use().
The community middleware wiki, linked from the README, is the canonical starting point for finding compatible packages.
No Bundled Middleware: The Composability Trade-off
Koa's minimal surface is a design choice with a real cost. Setting up a Koa application for a typical web project requires selecting and installing separate packages for routing, body parsing, and session handling, then understanding how each interacts with the others in the middleware stack. This setup work disappears in frameworks that bundle those components, such as Express.
The benefit of the opt-in model is that middleware composition is explicit. Every function in the stack is something the developer chose and placed there. Debugging an unexpected response transformation is a matter of checking the ordered list of app.use() calls, not searching for a built-in handler that runs before the user code.
The koajs GitHub organization maintains official packages including koa-router (for routing), koa-bodyparser (for request body parsing), and koa-static (for static file serving). These follow the same middleware contract as Koa's core and integrate through app.use(). Third-party middleware packages for Koa are listed on the repository's wiki page.
For teams who want a framework that includes routing, body parsing, and view rendering out of the box, Koa is not that framework. The composability model is most useful for projects with specific middleware requirements that differ from what an opinionated framework would provide by default.
Koa vs. Express: Middleware Model and Router Trade-offs
Express is the most common comparison point for Koa. Both are Node.js HTTP frameworks and both use a middleware model. The key difference, as documented in the docs/koa-vs-express.md file in the repository, is in the middleware execution model. Express uses callbacks and does not build the cascading before/after async pattern into its core. Koa builds that pattern in from the start.
The practical consequence shows up in middleware that needs to run code after the response is prepared. In Express, this requires careful callback management or the response-time middleware pattern. In Koa, the async/await cascade handles it naturally: any code after await next() runs after the downstream chain completes.
Express includes a built-in router. Koa does not. For a greenfield project, Koa requires adding koa-router or another routing package before the first route can be defined. For teams already familiar with Express who want async middleware and a cleaner context API without the generator-based approach from older Node.js versions, Koa is a direct upgrade path. The docs/koa-for-express-users.md file in the repository documents common Express patterns and their Koa equivalents.
The last push to the Koa repository was 2026-09-19. Version 3.2.1 was released on 2026-05-21. The project is MIT licensed. Community channels listed in the README include a Slack group (KoaJS Slack Group), a Reddit community at r/koajs, and a mailing list.
Editorial conclusion
Koa suits Node.js developers who want precise control over their middleware stack and are comfortable selecting and wiring every component themselves. It is not the right choice for teams who need a batteries-included framework with built-in routing, templating, and body parsing: those need to be added explicitly. Before starting, confirm that the target runtime meets the Node.js 18 or higher requirement stated in the README, and read the v2 to v3 migration guide in docs/migration-v2-to-v3.md if upgrading an existing project.
Frequently asked questions
What are the key differences between Koa.js and Express.js, and which one is better for Node.js development?
Koa uses async/await and a cascading middleware stack where each function can act before and after downstream middleware. Express uses callbacks and does not build the cascading pattern into its core. Koa ships no bundled middleware including no router; Express includes a router. Which is better depends on whether the team prioritizes explicit composition over a batteries-included starting point.
What Node.js version does Koa require?
Koa requires Node.js 18.0.0 or higher. The README states this requirement explicitly, as Koa depends on ES2015 features and native async function support.
Does Koa v3 still support the v1.x generator-based middleware signature?
No. The README states that old signature middleware support was removed in v3. The repository includes a migration guide at docs/migration-v2-to-v3.md covering the upgrade path from v2.x to v3.x.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/koajs-koa)
Community notes