Express Idempotency Middleware
raw JSON → 1.0.2 verified Sat Apr 25 auth: no javascript
Express middleware for idempotent POST requests using Idempotency-Key header (version 1.0.2, stable release, active development). Provides pluggable stores (Memory, Redis, Postgres), in-flight concurrency control with wait or reject strategies, and safe response replay with header whitelist. TypeScript-first, ESM-only, requires Node ≥18 and Express 4 or 5. Differentiators: built-in in-flight handling via wait timeout polling, stable response fingerprinting, and separate replay header whitelist for security-aware caching of location headers without cookies or auth tokens. Designed for payment, order, and webhook idempotency scenarios.
Common errors
error SyntaxError: Named export 'idempotencyMiddleware' not found. The requested module 'express-idempotency-middleware' is a CommonJS module which may not support all module.exports as named exports. ↓
cause Using CommonJS require() instead of ESM import
fix
Change to ESM import: import { idempotencyMiddleware } from 'express-idempotency-middleware' or use dynamic import()
error TypeError: store.get is not a function ↓
cause Custom store does not implement required store interface (get, set, delete methods)
fix
Ensure custom store implements Store interface with get(key), set(key, value, ttl?), and delete(key) async methods
error Idempotency-Status: conflict (409) ↓
cause Idempotency-Key reused with different request body or method than original
fix
Ensure all retries use exactly the same request body, headers (except whitelist), and method
Warnings
breaking ESM-only package: require() throws ERR_REQUIRE_ESM ↓
fix Use ESM imports: import { idempotencyMiddleware } from 'express-idempotency-middleware'
gotcha MemoryStore does not persist across server restarts; use Redis or Postgres store in production ↓
fix Implement custom store implementing Store interface or use provided examples for RedisStore/PostgresStore
gotcha Idempotency-Key is case-sensitive and must be a string; omit or empty key with requireKey:false returns 400 ↓
fix Always send a valid non-empty Idempotency-Key header, or set requireKey:true to enforce
deprecated Node.js <18 is not supported; engines field specifies >=18.0.0 ↓
fix Upgrade Node.js to version 18 or later
Install
npm install express-idempotency-middleware yarn add express-idempotency-middleware pnpm add express-idempotency-middleware Imports
- idempotencyMiddleware wrong
const { idempotencyMiddleware } = require('express-idempotency-middleware')correctimport { idempotencyMiddleware } from 'express-idempotency-middleware' - MemoryStore wrong
import MemoryStore from 'express-idempotency-middleware/MemoryStore'correctimport { MemoryStore } from 'express-idempotency-middleware' - IdemOptions wrong
import { IdemOptions } from 'express-idempotency-middleware'correctimport type { IdemOptions } from 'express-idempotency-middleware'
Quickstart
import express from 'express';
import { idempotencyMiddleware, MemoryStore } from 'express-idempotency-middleware';
const app = express();
app.use(express.json());
const store = new MemoryStore();
app.post(
'/payments',
idempotencyMiddleware({
store,
ttlMs: 24 * 60 * 60 * 1000,
inFlight: { strategy: 'wait', waitTimeoutMs: 3000, pollMs: 100 },
replay: { headerWhitelist: ['location'] }
}),
async (req, res) => {
const orderId = 'ord_' + Math.random().toString(36).slice(2);
res.setHeader('Location', `/orders/${orderId}`);
res.status(201).json({ orderId });
}
);
app.listen(3000);