Koa & Polka
Understand Koa and Polka as lightweight Node HTTP frameworks you may encounter in legacy codebases or minimal deployments.
Search across all documentation pages
Understand Koa and Polka as lightweight Node HTTP frameworks you may encounter in legacy codebases or minimal deployments.
Quick-reference for recognizing each framework.
Koa (async context):
import Koa from "koa";
const app = new Koa();
app.use(async (ctx, next) => {
const start = Date.now();
await next();
ctx.set("X-Response-Time", `${Date.now() - start}ms`);
});
app.use(async (ctx) => {
ctx.body = { ok: true };
});
app.listen(3000);Polka (minimal router):
import polka from "polka";
const app = polka();
app.get("/users", (_req, res) => {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify([{ id: 1 }]));
});
app.listen(3000);When to reach for this: Maintaining legacy Koa apps, or when you need the absolute smallest HTTP router (Polka).
Side-by-side comparison of the same endpoint:
// --- Koa ---
import Koa from "koa";
import Router from "@koa/router";
import bodyParser from "koa-bodyparser";
const koaApp = new Koa();
const router = new Router({ prefix: "/api" });
koaApp.use(bodyParser());
router.get("/users/:id", async (ctx) => {
ctx.body = { id: ctx.params.id, name: "Ada" };
});
koaApp.use(router.routes());
// --- Polka ---
import polka from "polka";
import { json } from "body-parser";
const polkaApp = polka();
polkaApp.use(json());
polkaApp.get("/api/users/:id", (req, res) => {
const id = (req as { params: { id: string } }).params.id;
res.end(JSON.stringify({ id, name: "Ada" }));
});
// --- Modern equivalent: Hono ---
import { Hono } from "hono";
const honoApp = new Hono();
honoApp.get("/api/users/:id", (c) => c.json({ id: c.req.param("id"), name: "Ada" }));What this demonstrates:
ctx (context) instead of (req, res)next() callback)| Factor | Koa | Polka | Hono | Express 5 |
|---|---|---|---|---|
| Size | Small | Tiny (~200 lines) | ~14KB | Medium |
| Middleware | Async ctx | Node (req, res) | Web Standard | (req, res, next) |
| Ecosystem | Mature but declining | Minimal | Growing fast | Largest |
| Edge support | No | No | Yes | No |
| Active maintenance | Maintained | Maintained | Very active | Active |
@koa/router, koa-bodyparser, koa-jwtsirv-cli and @sveltejs/kit adapter internalskoa-error-handler.body-parser middleware.@hono/zod-validator.| Alternative | Use When | Don't Use When |
|---|---|---|
| Hono | New lightweight project | Maintaining existing Koa app |
| Fastify 5 | Performance + schema validation | Absolute minimum size |
| Express 5 | Team familiarity | Edge deployment needed |
| Keep Koa | Existing stable codebase | Greenfield project |
When you need edge portability or active ecosystem growth. If Koa app is stable and low-churn, migration cost may not justify.
Not dead, but declining. Maintained but fewer new projects. Express and Fastify dominate new Node APIs.
Luke Edwards built it as the smallest usable HTTP router. Useful when you need routing without framework overhead.
Yes. @types/koa and @koa/router have type definitions. Less ergonomic than Hono's built-in types.
Koa async middleware uses await next() (no callback). Errors propagate naturally in async chains. See Middleware Pattern.
Yes for simple internal services. You bring all middleware, validation, and error handling yourself.
Rewrite routes as Fastify plugins with JSON Schema. Koa ctx maps to Fastify req/reply. Plan a dedicated sprint.
No official Koa adapter. NestJS supports Express and Fastify only.
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.
Reviewed by Chris St. John·Last updated Jul 18, 2026