{"id":17114,"library":"middleware-io","title":"Modern Promise-Based Middleware","description":"middleware-io is a lightweight, zero-dependency library for composing promise-based middleware in JavaScript and TypeScript applications. It provides a `compose` function similar to `koa-compose` and a `Composer` class for building middleware chains with various utility 'snippets' like lazy loading, forking, and concurrency control. The library is written in TypeScript, ensuring type safety and a robust development experience. Currently at version 2.8.1, its release cadence has been irregular since its active development phase around 2019-2021, with the latest significant changes related to `exports` in `package.json` for modern module resolution. Key differentiators include its self-sufficiency (zero dependencies), native ESM support, and a rich set of built-in middleware snippets.","status":"maintenance","version":"2.8.1","language":"javascript","source_language":"en","source_url":"https://github.com/negezor/middleware-io","tags":["javascript","typescript","middleware","compose","ware","promise","async","await","modern"],"install":[{"cmd":"npm install middleware-io","lang":"bash","label":"npm"},{"cmd":"yarn add middleware-io","lang":"bash","label":"yarn"},{"cmd":"pnpm add middleware-io","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"The `compose` function is a named export. ESM is preferred. CommonJS `require` might fail due to `exports` field in `package.json` since v2.7.0.","wrong":"const compose = require('middleware-io')","symbol":"compose","correct":"import { compose } from 'middleware-io'"},{"note":"The `Composer` class is a named export. Requires a generic type with an `object` restriction since v2.4.0, e.g., `Composer<MyContext>`.","wrong":"const Composer = require('middleware-io').Composer","symbol":"Composer","correct":"import { Composer } from 'middleware-io'"},{"note":"This is a TypeScript type import. It allows type-checking middleware functions without importing runtime code.","symbol":"Middleware","correct":"import type { Middleware } from 'middleware-io'"}],"quickstart":{"code":"import { compose } from 'middleware-io';\n\ninterface MyContext {\n  now?: number;\n  customData?: string;\n}\n\nconst composedMiddleware = compose<MyContext>([\n  async (context, next) => {\n    // This is the first middleware in the chain.\n    console.log('Step 1: Before next() in first middleware');\n\n    // Pass control to the next middleware in the stack.\n    await next();\n\n    // Control returns here after subsequent middleware complete.\n    console.log('Step 4: After next() in first middleware');\n\n    // Access data modified by later middleware.\n    console.log(`Context.now from next middleware: ${context.now}`);\n  },\n  async (context, next) => {\n    // This is the second middleware.\n    console.log('Step 2: Before next() in second middleware');\n\n    // Modify the context object, which is shared across the chain.\n    context.now = Date.now();\n    context.customData = 'Hello from second middleware!';\n\n    // Pass control to the next middleware (or the final handler if no more middleware).\n    await next();\n\n    // Control returns here after the next middleware (or final handler) completes.\n    console.log('Step 3: After next() in second middleware');\n  }\n]);\n\n// Execute the composed middleware with an initial context and a final handler.\ncomposedMiddleware({}, () => {\n  console.log('Final handler reached (no more middleware).');\n  return Promise.resolve(); // Ensure the final handler also returns a Promise\n})\n  .then(() => {\n    console.log('Middleware chain finished work successfully.');\n  })\n  .catch(console.error);\n","lang":"typescript","description":"This example demonstrates basic promise-based middleware composition, context modification, and asynchronous flow control using `compose`."},"warnings":[{"fix":"Upgrade your Node.js runtime to version 12.0.0 or newer. Check your `engines` field in `package.json`.","message":"Node.js 10 and 8 support was dropped in versions 2.8.0 and 2.2.0 respectively. The library now requires Node.js >=12.0.0.","severity":"breaking","affected_versions":">=2.2.0"},{"fix":"Change `import middlewareIO from 'middleware-io'` to `import { compose } from 'middleware-io'` and refactor code using `MiddlewareStatus`.","message":"Version 2.0.0 changed the main export to `compose` by default and removed `MiddlewareStatus`. Ensure your imports are updated to use named imports for `compose`.","severity":"breaking","affected_versions":">=2.0.0"},{"fix":"Review calls to affected snippets and `Composer` instantiation, updating argument order and providing a generic type for `Composer` (e.g., `new Composer<MyContext>()`).","message":"In v2.4.0, the order of arguments for `getBeforeMiddleware` and `getEnforceMiddleware` snippets was reversed. Additionally, the `Composer` class now requires a generic type with an `object` restriction.","severity":"breaking","affected_versions":">=2.4.0"},{"fix":"Always use named `import` statements (e.g., `import { compose } from 'middleware-io'`). If using CommonJS, ensure your environment supports `exports` map resolution or consider using dynamic `import()` for ESM-only packages.","message":"Since v2.7.0, the library uses the `exports` field in `package.json` for module resolution. This can lead to issues with older tooling or environments that do not correctly support `exports`, particularly for CommonJS `require()` statements trying to access deep paths.","severity":"gotcha","affected_versions":">=2.7.0"},{"fix":"Review your middleware logic, especially around `next()` calls, to ensure compatibility with `koa-compose`'s single `next()` invocation policy. Update `Composer` instantiation with generics where appropriate.","message":"In v2.5.0, `Composer` gained an inherited generic, and `compose` was aligned to correspond with `koa-compose` behavior. This might subtly change how middleware functions are expected to behave, especially concerning multiple `next` calls.","severity":"gotcha","affected_versions":">=2.5.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure your project is set up for ES Modules (`\"type\": \"module\"` in `package.json`) and use `import { Symbol } from 'middleware-io'` syntax. Alternatively, use dynamic `import()`: `const { Symbol } = await import('middleware-io')`.","cause":"Attempting to `require()` the package in a CommonJS environment, but the package is primarily designed for ESM with its `exports` field in `package.json`.","error":"Error [ERR_REQUIRE_ESM]: require() of ES Module ... not supported."},{"fix":"Verify your `tsconfig.json` `module` setting (e.g., `\"ESNext\"` or `\"NodeNext\"`) and `moduleResolution`. Ensure you are using named imports: `import { compose } from 'middleware-io'`.","cause":"This typically occurs in transpiled environments (like some Babel or TypeScript configurations targeting CommonJS) where a named ESM import (`import { compose } from 'middleware-io'`) is incorrectly converted, or if `compose` was previously a default export.","error":"TypeError: (0 , middleware_io_1.compose) is not a function"},{"fix":"Explicitly provide a generic type to `compose` or `Composer` that matches your context object, e.g., `compose<MyContext>(...)` or `new Composer<MyContext>()`.","cause":"The generic type for `Composer` or `compose` is not correctly inferred or provided, leading to type mismatch errors with the `context` object in your middleware functions.","error":"Argument of type '(...args: any[]) => Promise<any>' is not assignable to parameter of type 'Middleware<object>'."}],"ecosystem":"npm","meta_description":null}