# follow-redirects gives Node's http and https a redirect-following wrapper

> follow-redirects is a small MIT licensed Node module that exposes http and https objects behaving like the built-in ones but following redirects, with per request hooks for rewriting options and stripping credentials. It is the plumbing behind a lot of Node HTTP work, and its maintenance is currently paused because it is unfunded.

**follow-redirects/follow-redirects** — Node.js module that automatically follows HTTP(S) redirects

- Repository: https://github.com/follow-redirects/follow-redirects
- Website: https://www.npmjs.com/package/follow-redirects
- Stars: 580 · Forks: 190
- Language: JavaScript
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/follow-redirects-follow-redirects

## A wrapper, not a fork, of the built-in modules

follow-redirects provides request and get methods that behave identically to those found on the native http and https modules, with the exception that they follow redirects automatically. That framing is the design in one sentence, and it explains why the package is so widely used without being a large library. The top level of the repository is small and legible. There is index.js, http.js, https.js and a debug.js, plus a test/ directory, an .eslintrc, a .nycrc for coverage configuration and a SECURITY.md. The package manifest declares the main entry as index.js, ships only the top level .js files, and requires Node 4.0 or newer, which tells you the code avoids modern syntax on purpose. The author's stated motivation for the whole project is not that redirects are hard, but that everybody needs them and nobody wants to write the same loop again.

## The maintenance pause, stated at the top of the page

The first thing on the page is a funding notice, and it is not a small detail. The header reads that follow-redirects is in need of funding, with an important note stating that maintenance is paused until funding is found. The notice gives the scale: the package is downloaded over 400 million times per month and has been maintained for over ten years by one volunteer who has no funds to provide update and security guarantees. What this means for you is spelled out directly. The package stays published and keeps working as it does today, but there are no guarantees of bug fixes, security fixes, or replies to issues and pull requests, and security reports are handled best-effort only, with SECURITY.md as the reference. The notice also says what could restart maintenance, and the arithmetic is stated in the same breath: even if only 0.1% of downloads paid $0.01 the project would be fully funded with $4000 per month, and that is not the case, and that is okay, but also insufficient to continue, because security triage, CVE handling, fixes and releases all need covering. Companies that depend on the package, directly or through another library, are asked to sponsor on GitHub or to email about invoice-based funding or a security support agreement.

## The basic usage pattern, and reading the final URL

The module is used by requiring it and taking the http and https properties off the export, and the call shape is the built-in one.

```javascript
const { http, https } = require('follow-redirects');

http.get('http://en.wikipedia.org/', response => {
  response.on('data', chunk => {
    console.log(chunk);
  });
}).on('error', err => {
  console.error(err);
});
```

One property is worth knowing because it is the answer to the question people usually have. You can inspect the final redirected URL through the responseUrl property on the response, and if no redirection happened, responseUrl is the original request URL. So a caller can always tell where the request actually ended up, which is what you need when you are debugging a shortener or an auth flow.

```javascript
const request = https.request({
  host: 'en.wikipedia.org',
  path: '/',
}, response => {
  console.log(response.responseUrl);
  // 'http://duckduckgo.com/robots.txt'
});
request.end();
```

That last call is a small demonstration of the behaviour. A request to a host that redirects lands you somewhere else entirely, and the responseUrl shows it.

## Global limits and the per-request option set

Two limits exist and both are enforced by emitting an error. maxRedirects defaults to 21 and sets the maximum number of allowed redirects, and maxBodyLength defaults to 10MB and sets the maximum size of the request body. They can be set globally on the module itself.

```javascript
const followRedirects = require('follow-redirects');
followRedirects.maxRedirects = 10;
followRedirects.maxBodyLength = 20 * 1024 * 1024; // 20 MB
```

The same two options exist per request, set by passing an options object, and they sit alongside five others. followRedirects defaults to true and decides whether redirects should be followed at all. beforeRedirect defaults to undefined and lets you change the request options on redirects or abort the request by throwing an error. agents defaults to undefined and sets the agent option per protocol, since HTTP and HTTPS use different agents, with the example value being an object holding an http.Agent and an https.Agent. trackRedirects defaults to false and controls whether the redirected response details are stored into the redirects array on the response object. sensitiveHeaders defaults to an empty array and names headers to omit when making redirected requests, with the documentation naming X-API-Key and X-Auth-Token as examples. That last option is the one to read carefully before deploying, because a credential header that follows a redirect to a host you did not choose is a credential leak, and the default is to forward everything.

## beforeRedirect: rewriting the request on each hop

The beforeRedirect hook is the mechanism that makes the module more than a redirect counter, and the documented example is worth reading in full because it shows the available context.

```javascript
const url = require('url');
const { http, https } = require('follow-redirects');

const options = url.parse('http://en.wikipedia.org/');
options.maxRedirects = 10;
options.beforeRedirect = (options, response, request) => {
  // Use this to adjust the request options upon redirecting,
  // to inspect the latest response headers,
  // or to cancel the request by throwing an error

  // response.headers = the redirect response headers
  // response.statusCode = the redirect response code (eg. 301, 307, etc.)

  // request.url = the requested URL that resulted in a redirect
  // request.headers = the headers in the request that resulted in a redirect
  // request.method = the method of the request that resulted in a redirect
  if (options.hostname === "example.org") {
    options.auth = "user:password";
  }
};
http.request(options);
```

The hook receives three things: the options object that will be used for the next request, the response that triggered the redirect, and the request that produced it. From the response you get the headers and the status code, so you can distinguish a 301 from a 307. From the request you get the url, the headers and the method, so you can see exactly what is being re-sent. And the options are mutable, so you can attach credentials to a specific host as the example does, which is the correct way to handle a redirect that lands on a host requiring authentication. Throwing inside the hook aborts the request, which gives you a clean cancellation path rather than a half followed chain.

## Wrapping a custom protocol, and the browser substitution trick

By default, follow-redirects will use the Node.js default implementations of http and https. To enable features such as caching and intermediate request tracking, you might instead want to wrap follow-redirects around custom protocol implementations, which is done through the wrap export.

```javascript
const { http, https } = require('follow-redirects').wrap({
  http: require('your-custom-http'),
  https: require('your-custom-https'),
});
```

Such custom protocols only need an implementation of the request method, which is a low bar, and the payoff is that anything you have layered on top of the standard modules, a cache, a retry policy, an instrumented client, still participates in the redirect handling. The browser case is a different trick entirely. Due to the way the browser works, the http and https browser equivalents perform redirects by default, so requiring the package this way lets you tell webpack and friends to replace follow-redirects by the built-in versions.

```json
{
  "follow-redirects/http"  : "http",
  "follow-redirects/https" : "https"
}
```

That configuration block is a bundler alias mapping, and the spacing in it is unusual enough to be worth copying exactly rather than reformatting, since some alias resolvers are strict about the key. The result is that a browser bundle pulls in the browser build of the package, which does not need to do the following itself because the browser already does it.

## Where a redirect-following client stops being the right answer

There are situations where this module is the wrong shape of solution. The first is when you need to know that a redirect happened rather than to follow it, since the module's whole purpose is to hide the redirect, and turning on trackRedirects recovers the information at the cost of the simpler default. The second is the credential case, and it deserves more than a footnote. A module that follows a redirect by default will re-send your request headers to whatever host the redirect names, and if that host is not the one you intended, an Authorization header or an API key goes with it. The sensitiveHeaders option exists for that, but it is off by default, so a service that fetches URLs from user input needs to configure it rather than assume the library is safe there. The third is the browser bundle, where the module does almost nothing because the browser follows redirects on its own, so shipping it there is dead weight. And the fourth is the one that should decide an adoption for a new project, which is the funding notice. A package with 400 million monthly downloads and a single volunteer maintainer is a concentration risk, and the README is candid that security fixes and releases are what the money is meant to cover.

## Conclusion

Adopt follow-redirects if you are writing Node code that fetches URLs whose final location you do not control, because the alternative is hand rolling redirect handling, status code checks and header rewriting in every call site. Do not adopt it in a new service that has a strict dependency policy, since the project has paused maintenance until funding is found and the README states there are no guarantees of bug fixes, security fixes or replies to issues and pull requests. Verify two things before you depend on it: that you understand the sensitiveHeaders option, because the default behaviour forwards your headers across a redirect to another host, and that the version you pin behaves the way you expect, since the module version in the manifest and the published release tags do not obviously line up. The practical first step is to add the package, set maxRedirects and maxBodyLength on the module rather than per request, and then read the responseUrl property on the response so you know where the request actually landed.

## FAQ

### What does follow-redirects do in Node.js?

It provides request and get methods that behave identically to those of the native http and https modules, with the exception that they follow redirects automatically. You can inspect the final URL through the responseUrl property on the response, which is the original request URL if no redirect happened.

### Is follow-redirects still maintained?

The project states that maintenance is paused until funding is found. The package stays published and keeps working, but there are no guarantees of bug fixes, security fixes, or replies to issues and pull requests, and security reports are handled best-effort only. The last push to the repository was on 2026-10-08.

### What does the sensitiveHeaders option do?

It names headers to omit when making redirected requests, and it defaults to an empty array. The documentation names X-API-Key and X-Auth-Token as examples, which matters because by default headers are carried across a redirect to another host.

### How do I change the redirect limit in follow-redirects?

maxRedirects defaults to 21 and can be set globally on the module or per request through the options object. Exceeding the limit emits an error. The same applies to maxBodyLength, which defaults to 10MB and limits the request body size.

### How do I use beforeRedirect in follow-redirects?

Set it on the options object as a function taking the next options, the response that caused the redirect and the request that produced it. You can adjust the options for the next hop, inspect the redirect response headers and status code, or throw an error to abort the request.

## Sources

- [follow-redirects/follow-redirects on GitHub](https://github.com/follow-redirects/follow-redirects)
- [License: MIT](https://github.com/follow-redirects/follow-redirects/blob/main/LICENSE)
- [Project website](https://www.npmjs.com/package/follow-redirects)
- [README](https://github.com/follow-redirects/follow-redirects/blob/main/README.md)
- [Releases](https://github.com/follow-redirects/follow-redirects/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/follow-redirects-follow-redirects
