http-proxy-middleware: a Node.js reverse proxy for express, next.js and hono
:zap: The one-liner node.js http-proxy (httpxy) middleware for connect, express, next.js and more
At a glance
- What is it?
- http-proxy-middleware wraps the httpxy proxy in a connect-style middleware, so an existing Node server can forward /api traffic without a separate nginx container. The v4 line is a rewrite with a plugin system and a hono entry point, and it is worth checking the migration notes before upgrading from v2.
- Who is it for?
- Adopt it when your proxy rules belong next to your routes: an express, connect, polka, fastify, hono or next.js app that needs to forward a path prefix, rewrite it, or intercept request and response bodies in JavaScript. Skip it when the proxy is infrastructure rather than application code, when you need TLS termination, load balancing or rate limiting that nginx and Caddy already provide, or when you cannot absorb a major-version migration.
- 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 5 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The Node.js proxy problem http-proxy-middleware solves
A front end running on localhost:3000 talks to an API on another origin. The browser blocks the cross-origin call, cookies do not attach cleanly, and the API's URL leaks into client code. The usual fixes are a dev-server proxy entry, a reverse proxy in front of everything, or a middleware mounted inside the Node server that is already running. http-proxy-middleware is the third option. It is for teams whose application server is the natural place to express routing rules, and who would rather write those rules in TypeScript than in an nginx config that lives in a different repository.
The package describes itself as "the one-liner node.js http-proxy (httpxy) middleware for connect, express, next.js and more". The parenthetical matters. Since v4 the proxying is done by httpxy, which the README calls "a maintained version of http-proxy". That is the real reason this project exists in its current form: the original node-http-proxy went quiet, and http-proxy-middleware moved its transport layer to a fork that still receives fixes. If you are choosing between the two, the difference is not the middleware API, it is who is patching the socket handling underneath.
The audience is narrow but deep. Express and connect servers, next.js custom servers, hono apps (there is a dedicated ./hono export in package.json), polka, fastify, and browser-sync or gulp setups that already mount middleware. The repository ships examples for express, connect, fastify, hono, next-app, http-server, browser-sync, websocket, sse and response-interceptor, which is a fair map of who the maintainers expect to show up.
How createProxyMiddleware routes a request
The core call is createProxyMiddleware(config), which returns a request handler you mount on a server. The handler inspects the incoming request, decides whether it matches, optionally rewrites the path, and hands the request to httpxy, which opens the outbound connection and pipes the response back. Everything above that transport is configuration.
Two options do most of the work. options.target is the destination, protocol plus host, and it can include a base path. options.changeOrigin rewrites the Host header, which the README says is needed "for virtual hosted sites" and links to the name-based virtual hosting article on Wikipedia. Get changeOrigin wrong against a host that routes by Host header and you will reach the wrong virtual host, or get a 404 from a server that is definitely running.
Matching is handled by pathFilter, which accepts a string, an array of strings, a glob, an array of globs, or a function. The README is precise about the input: "The path used for filtering is the request.url pathname. In Express, this is the path relative to the mount-point of the proxy." That sentence resolves most confusion about why a filter behaves differently under app.use('/api', proxy) than under app.use(proxy). Glob matching is done by micromatch, so '**/*.html' matches any path ending in .html and '**' matches everything.
Beyond matching, pathRewrite changes the outgoing path, router picks a target per request from an object or a function, and plugins is an array that hooks into the request and response lifecycle. ejectPlugins, default false, controls whether the built-in plugins stay in the chain. The README also documents a definePlugin helper and a logger option, which is how you get visibility into what the proxy is doing without attaching a debugger.
Installing http-proxy-middleware and proxying /api in express
Installation is a single npm command, and the README marks it as a dev dependency:
npm install --save-dev http-proxy-middlewareThe package is ESM-first. package.json sets "type": "module" and the exports map points "." at ./dist/index.js with types at ./dist/index.d.ts, so an import statement is the expected form. The README's express example mounts the proxy at a path prefix:
import express from 'express';
import { createProxyMiddleware } from 'http-proxy-middleware';
const app = express();
const exampleProxy = createProxyMiddleware({
target: 'http://www.example.org/api',
changeOrigin: true,
});
app.use('/api', exampleProxy);
app.listen(3000);A request to http://127.0.0.1:3000/api/foo/bar is forwarded to http://www.example.org/api/foo/bar. The base path is preserved because target carries /api and the mount point does too. If you want the proxy to decide matching rather than the server, drop the path argument and use pathFilter instead:
app.use(
createProxyMiddleware({
target: 'http://www.example.org/api',
changeOrigin: true,
pathFilter: '/api/proxy-only-this-path',
}),
);For hono, package.json exposes a separate entry point at ./hono, resolved to ./dist/index-hono.js. The examples directory contains a subpath.hono.shim.js alongside the ordinary subpath.shim.js, which is where the two mounting styles diverge. Start from examples/express or examples/hono rather than from the README snippet if your server is not plain express.
WebSocket upgrades, SSE and response interception
Proxying plain HTTP is the easy half. WebSocket traffic arrives as an HTTP upgrade request, and the README has a dedicated section for it plus an example directory at examples/websocket. There is also an "External WebSocket upgrade" subsection, which matters when something else in your stack already owns the upgrade event and you need to hand it to the proxy deliberately rather than letting the middleware attach its own listener. Two listeners on the same upgrade event is a classic source of a connection that opens and then does nothing.
Server-sent events get their own example at examples/sse. SSE is a long-lived response with a specific content type, and a proxy that buffers the response body will hold events until the buffer flushes, which looks like a hung stream. The response-interceptor example shows the other direction: reading and modifying what comes back. The README has sections titled "Intercept and manipulate requests" and "Intercept and manipulate responses", so both hooks are supported, but interception means your code now touches every proxied payload. For large binary responses that is a cost you should measure rather than assume.
The plugin array is the structured way to do this. A plugin registered through plugins participates in the request and response lifecycle, and definePlugin is the helper for writing one. This is the main architectural difference from v2, where interception was done by subscribing to httpxy events directly. The README still documents httpxy events and httpxy options separately, so the older style remains available, but new code should probably start with a plugin.
Where http-proxy-middleware is the wrong tool
The README has a section headed "Node.js 17+: ECONNREFUSED issue with IPv6 and localhost (#705)". That is a real failure mode with a real issue number, and it is the kind of thing you hit on a fresh developer machine rather than in production. If you are proxying to localhost on a modern Node version and getting connection refused from a service that is plainly up, read that section before you debug anything else.
More broadly, this is application-level proxying. It does not terminate TLS, it does not do load balancing across upstreams, it does not rate limit, and it does not serve static files. If your proxy exists to sit in front of several services and route by hostname, nginx or Caddy does that in a config file that operations can change without a deploy. Putting the same rules in middleware means every routing change is a code change, a review, and a release. That is the trade you are making, and it is only worth making when the rules genuinely depend on application state.
The version situation deserves attention too. The README states it is showing documentation for v4.x.x, and links older documentation for v3.0.5, v2.0.4 and v0.21.0 separately. The repository carries both MIGRATION.md and MIGRATION_V3.md at the top level, which tells you the v2 to v4 jump is not a rename. The recent release list shows v4.2.0 alongside v2.0.10 and v2.0.10-beta.0, so the v2 line is still receiving releases. If you are on v2 and working, that is a supported place to be.
http-proxy-middleware compared with express-http-proxy and nginx
express-http-proxy is the closest alternative in the same ecosystem, and the difference is in how the middleware is shaped. express-http-proxy is express-specific and centres on per-request hooks, so its API reads as a set of callbacks for decorating a request before it leaves and a response before it returns. http-proxy-middleware is server-agnostic (connect, express, polka, fastify, hono, next.js) and centres on a configuration object plus a plugin array, with the transport delegated to httpxy. If you are on express and want to write imperative hooks, express-http-proxy is a shorter path. If you might move servers, or you want the httpxy option surface, http-proxy-middleware is the more portable choice.
Against nginx the split is not features, it is location. nginx is a separate process with its own config language, reload semantics and operational story. It handles TLS, upstream pools, caching and rate limiting that this package does not attempt. http-proxy-middleware lives inside your process, which means it can read application config, share the same logger, and be covered by the same test suite as your routes. Neither is better in the abstract. The question is whether the routing rule is infrastructure or application logic.
One more comparison worth naming: the README positions httpxy as "a maintained version of http-proxy", and the related searches include Node-http-proxy. If you are currently wiring node-http-proxy directly into an express app, http-proxy-middleware is the same transport with a middleware wrapper and a plugin system on top. The migration is mostly about moving from event subscriptions to options and plugins.
Maintenance, licence and the cost of staying current
The repository is not archived, and the last push was on 2026-09-12, nine days before this writing. The most recent release is v4.2.0 from 2026-07-04, and the v2 line saw v2.0.10 on 2026-06-19. That is a project with an active release cadence on two lines simultaneously, which is good for people who cannot migrate yet and a hint that the maintainers are absorbing the cost of supporting both.
The licence is MIT. For most teams that means the usual obligations apply: keep the copyright notice and the licence text with distributed copies. It says nothing about whether the project accepts contributions to a given feature, and nothing about support commitments. CONTRIBUTING.md and AGENTS.md at the repository root are where the actual process lives. This is not legal advice; if your organisation has rules about dependency licences, route it through whoever normally handles that.
The upgrade cost is the part people underestimate. Two migration documents exist for a reason, and the v4 README explicitly separates itself from the v3.0.5, v2.0.4 and v0.21.0 documentation trees. The plugin system, ejectPlugins and the hono entry point are v4 concepts. If your codebase subscribes to httpxy events directly, that still works, but it is the old shape. Budget the migration as a real task with test coverage on your proxy paths, not as a version bump in package.json.
Editorial conclusion
Adopt it when your proxy rules belong next to your routes: an express, connect, polka, fastify, hono or next.js app that needs to forward a path prefix, rewrite it, or intercept request and response bodies in JavaScript. Skip it when the proxy is infrastructure rather than application code, when you need TLS termination, load balancing or rate limiting that nginx and Caddy already provide, or when you cannot absorb a major-version migration. Before committing, read MIGRATION_V3.md and MIGRATION.md for the jump from v2, confirm which httpxy options your target requires, and check the v4 README section on the Node.js 17 and later ECONNREFUSED behaviour with IPv6 and localhost, because that one bites on a fresh machine rather than in production.
Frequently asked questions
How do I install http-proxy-middleware?
Install it from npm with the command the README gives, npm install --save-dev http-proxy-middleware. The package is ESM-first, so import createProxyMiddleware from 'http-proxy-middleware' rather than using require.
How do I use http-proxy-middleware?
Call createProxyMiddleware with a config object containing target and changeOrigin, then mount the returned handler on your server, for example app.use('/api', exampleProxy). The README's express example forwards http://127.0.0.1:3000/api/foo/bar to http://www.example.org/api/foo/bar.
What is http-proxy-middleware?
It is a Node.js proxy middleware for connect, express, next.js, hono and other servers, described in its README as the one-liner node.js http-proxy (httpxy) middleware. Since v4 the actual proxying is performed by httpxy, which the README calls a maintained version of http-proxy.
Is there an alternative to http-proxy-middleware?
express-http-proxy is the closest alternative in the same ecosystem, but it is express-specific and built around per-request callbacks rather than a configuration object plus a plugin array. For proxy rules that belong to infrastructure rather than application code, nginx handles TLS, upstream pools and rate limiting that this package does not attempt.
How does http-proxy-middleware compare with nginx?
nginx runs as a separate process with its own config language and handles TLS termination, load balancing and rate limiting. http-proxy-middleware runs inside your Node process, so its routing rules can read application config and ship with your code, but every routing change becomes a code change and a release.
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/chimurai-http-proxy-middleware)