The npm request package has been fully deprecated since February 11, 2020, and so have its promise wrappers request-promise and request-promise-native — which means no security fixes are coming, and continuing to depend on them is a slow-building risk rather than a bug you can point to today. For years, request npm was the default HTTP client for Node.js, and its ergonomics were the reason projects reached for request-promise npm to get async/await support on top. That popularity is exactly why the deprecation matters: enormous amounts of code still pull it in.
Deprecation is not the same as "broken." The package still installs and still works. But from a security standpoint, an unmaintained package sitting in your dependency tree is a liability that grows with time, and understanding why is more useful than a scary headline.
What "deprecated" actually means here
When the request maintainers deprecated the package, they were explicit: no new changes are expected to land, and none had for some time before the announcement. The stated reason was practical. request predates the modern JavaScript paradigm of promises and async/await, and retrofitting it cleanly was not feasible, so the maintainers chose to stop rather than half-migrate a package that millions of projects depended on.
The knock-on effect hit the wrappers immediately. request-promise npm and request-promise-native were both deprecated on the same day, because both exist only to add promise support to request. The npm request-promise page and the request promise npm ecosystem all carry the same deprecation notice for the same reason: they extend a package that is no longer maintained.
Why an unmaintained HTTP client is a security concern
An HTTP client is not a trivial dependency. It handles URL parsing, redirects, TLS, proxies, cookies, and header processing — all areas where subtle flaws turn into real vulnerabilities like request smuggling, SSRF via redirect handling, or improper certificate validation. When a package in that role stops receiving maintenance, three things follow:
- New vulnerabilities will not be patched. If a flaw is found in request's redirect or proxy handling tomorrow, there is no maintainer to ship a fix. You would be left patching a fork yourself or ripping it out under pressure.
- Its dependencies age too. request pulls in a tree of its own transitive dependencies. Some of those have themselves seen advisories over the years, and with request frozen, the pinned versions do not move forward. Your exposure is the whole tree, not just the top package.
- It signals staleness. A dependency deprecated years ago is often a marker that a project is not tracking its supply chain closely, which tends to correlate with other neglected updates.
None of this is "request has a critical CVE you must patch now." It is the quieter risk that unmaintained code accretes exposure while you are not looking. That is precisely the kind of thing a software composition analysis scan is built to surface — it will flag request and its tree as deprecated and report any known advisories in the transitive dependencies, so the risk is visible instead of dormant.
The maintained alternatives
Moving off request is well-trodden ground; there are several solid replacements depending on what you need.
Native fetch. Modern Node.js ships a global fetch built in, so for many cases you need no dependency at all:
// no import needed on current Node.js
const res = await fetch('https://api.example.com/data', {
headers: { Authorization: `Bearer ${token}` },
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
Fewer dependencies is a security win in itself: the code you do not install cannot be compromised.
axios is a popular, actively maintained client with a request-like feel, interceptors, and automatic JSON handling. It is a comfortable migration target for code that leaned on request's convenience.
got is a maintained, promise-first client designed for Node.js with good defaults around retries and streams, and it maps cleanly onto patterns people used request-promise for.
The migration is usually mechanical. A typical request-promise call:
// old: request-promise (deprecated)
const rp = require('request-promise');
const body = await rp({ uri: url, json: true });
becomes, with native fetch:
const res = await fetch(url);
const body = await res.json();
Watch the behavioral differences: fetch does not throw on a 4xx or 5xx status (you check res.ok yourself), and query-string and body handling differ slightly across clients. Test the error paths specifically, since that is where request's implicit behavior differs most from its replacements.
Migrating without breaking things
A sane order of operations:
- Find every usage. Search for
require('request'),require('request-promise'), and their import forms across the codebase, and check your lockfile for transitive pulls you did not add directly. - Pick one replacement and standardize on it rather than mixing three clients.
- Migrate call sites in small batches, paying attention to status-code handling, redirects, and timeouts.
- Re-run your SCA scan after the change to confirm request and its tree are actually gone, not just unused in one file while still in the lockfile.
Transitive usage is the sneaky part. Even after you remove your own direct dependency, request can remain because something else you depend on still uses it. Those you cannot fix directly; you either wait for the upstream package to migrate, or replace that dependency too. Knowing which case you are in is the whole point of scanning the resolved tree rather than just your package.json.
FAQ
Is the npm request package deprecated?
Yes. The request package was fully deprecated on February 11, 2020. Its promise wrappers, request-promise and request-promise-native, were deprecated on the same day because they extend request.
Is it safe to keep using request?
It still functions, but no security fixes will ever be released for it, and its transitive dependencies are frozen. Over time that makes it a growing liability. Migrating to a maintained client is the safer path.
What should I use instead of request-promise?
Native fetch (built into modern Node.js) needs no dependency at all. For a request-like experience with more features, axios and got are both actively maintained and well suited to migrating request-promise code.
Why was request deprecated if it was so popular?
The maintainers judged that the package could not be cleanly adapted to modern JavaScript async/await patterns without a rewrite that would disrupt the millions of projects depending on it, so they chose to stop maintenance rather than half-migrate it.