Course contentsShow
← Node.js
Lesson 620 of 1,9807. Web Framework Architecture and MiddlewareFree lesson

The Express vs Koa Philosophy

Contrast callback-based waterfall processing with generator-driven promise chaining architectures.

In this lesson, you will learn how the architectural evolution from Express to Koa shifted middleware from a rigid, callback-driven waterfall to a flexible, promise-based "onion" model.

The Waterfall vs. The Onion

Express was built on a waterfall philosophy. When a request enters an Express application, it passes through a chain of middleware functions. Each function executes, optionally calls next(), and passes control down the line. Because this model relies heavily on callbacks, "waiting" for an asynchronous operation to finish—like a database query—often requires careful tracking of the call stack, as once you pass control to the next middleware, you cannot easily "return" to the previous one to finish work after the response has been sent.

Koa, created by the same team, introduced a generator-driven promise chaining architecture. This transforms the middleware into an "onion" structure. Instead of a one-way street, middleware can pause execution at await next(), let inner layers run, and then resume execution to perform final operations (like calculating response time or handling errors) after the inner layers have finished.

Comparing the Flow

In Express, if you want to log the time taken to process a request, you often have to rely on event listeners because the request-response cycle is unidirectional:

// Express (Waterfall)
app.use((req, res, next) => {
  console.log('Request received');
  next(); // You cannot easily 'come back' here after the response is sent
});

In Koa, you use async/await to control the flow, allowing the middleware to wrap the entire downstream execution:

// Koa (Onion/Promise Chaining)
app.use(async (ctx, next) => {
  const start = Date.now();
  await next(); // The middleware pauses here while inner layers run
  const ms = Date.now() - start; // It resumes here after the response is ready
  console.log(`Request took ${ms}ms`);
});

By leveraging promise chaining, Koa eliminates the "callback hell" inherent in waterfall systems, allowing developers to handle complex asynchronous flows—like custom error handling or logging—more cleanly by simply wrapping the await next() call.

Key Takeaway: While Express uses a linear callback waterfall, Koa utilizes an async-promise onion model that allows middleware to wrap and control the entire lifecycle of a request.