Free checker
Paste package.json and any JS/TS files. Separate files with a line like // lib/api.js to get per-file verdicts. Try a sample:
Before → after (what --fix does)
Before · request
const request = require('request'); request.get(url, { json: true, timeout: 5000 }, (err, res, body) => { if (err) return done(err); done(null, res.statusCode, body); });
After · native fetch (via generated shim)
const request = require('./lib/request-fetch.cjs'); request.get(url, { json: true, timeout: 5000 }, (err, res, body) => { if (err) return done(err); done(null, res.statusCode, body); });
One line changes. The generated lib/request-fetch.cjs (also .mjs and a strict .ts) is about 230 lines of plain code on top of fetch that you own. It keeps request's (err, res, body) callback, res.statusCode, json: true, qs, baseUrl, timeout → ESOCKETTIMEDOUT, "non-2xx is not an error", and request's exact redirect rules (POST is not followed by default). Options it does not support throw loudly instead of being silently ignored.
What you get on a real repo
Migration map
| request · request-promise | native fetch | Pack |
|---|---|---|
require('request') / import request from 'request' | ./lib/request-fetch.{cjs,mjs,ts} (native fetch inside) | ✓ auto |
request(url, opts, (err, res, body) => …), .get/.post/.put/.patch/.del/.head | same call, same (err, res, body), res.statusCode | ✓ unchanged |
json: true / json: {…}, qs, baseUrl, timeout, encoding: null | identical semantics (qs merge, ESOCKETTIMEDOUT, Buffer, parsed JSON) | ✓ unchanged |
request-promise, -native, -any | requestPromise (rejects non-2xx with StatusCodeError) | ✓ auto |
request(url).pipe(dest) | pipeline(Readable.fromWeb(res.body), dest) | flag + recipe |
form / formData / multipart | URLSearchParams / FormData + fs.openAsBlob() | flag + recipe |
jar, auth, oauth | cookie jar lib / authorization header | flag + recipe |
proxy, agentOptions, ca/cert, strictSSL | undici ProxyAgent / Agent as dispatcher | flag + recipe |
request.defaults({…}) | your own 5-line fetch helper | flag + recipe |
package.json deps, @types/request, engines.node < 18 | removed once unused · Node 22+ | ✓ deps / flag engines |
The 4 ways a hand rewrite breaks production
4xx/5xx suddenly throw (or stop throwing)
request's callback treats a 404 as success, request-promise rejects it, and fetch resolves it. Mix those up and your error handling inverts silently.json: true did three things
It serialized the body, set content-type/accept, and parsed the response, falling back to text on bad JSON. With raw fetch each one is a separate line you can forget.POST redirects
request does not follow redirects for POST/PUT/PATCH/DELETE unless you setfollowAllRedirects. fetch follows them. Payment and webhook calls change behaviour.Proxies disappear
request readHTTP_PROXY/HTTPS_PROXY by itself and fetch doesn't. Corporate and CI egress breaks on deploy, not in tests.Compared with the alternatives
| This pack | Community codemod | Hand rewrite | |
|---|---|---|---|
| Keeps request semantics (non-2xx, json, timeouts, redirect rules) | ✓ tested vs request 2.88.2 | - | you, by hand |
| Flags streams, formData, jar, auth, proxy, TLS with recipes | ✓ 30+ rules | partial | - |
| Never half-migrates a file | ✓ | - | - |
| Zero dependencies (no jscodeshift/Babel) | ✓ | - | ✓ |
| Dry-run diff, .bak backups, CI gate, Markdown report | ✓ | - | - |
| TypeScript (NodeNext / bundler / CJS) | ✓ tsc --strict | ? | ✓ |
How it works
node cli.js . --md report.md lists every finding with file:line and the fix.--dry-run prints the diff and writes nothing.--fix repoints safe imports (.bak backups), writes the shim and cleans package.json.--ci exits 1 while anything is left. Put it in your pipeline.request → fetch Migration Pack
- Codemod CLI (
node cli.js . --fix) forrequest,request-promise,-nativeand-any. It touches only files where every call is provably supported, writes .bak backups, and gives a--dry-rundiff. It never overwrites a file it didn't generate. - Generated fetch shims for CJS, ESM and TypeScript. The TS passes
tsc --strictunder NodeNext, bundler and CommonJS. Parity is tested against the real request 2.88.2. - Recipes for everything else: streams,
FormData, cookies, Basic/Bearer auth, undiciProxyAgent/EnvHttpProxyAgent, TLSAgent,defaults(). - CI gate and reports (
--ci,--json,--md), a migration checklist, 71 regression tests and fixtures. Zero dependencies.
Instant download: after checkout you go straight to your private download page. Runs locally on Node 18+.
Get the Migration Pack for $9Methodology
The free checker runs entirely in your browser: it matches the text you paste against rules written from the official changelogs and migration guides. Nothing is uploaded. The paid deliverables are files (codemod, templates, checklist) unlocked right after checkout; each pack is tested against the fixtures shipped inside it.
Sources and free assets: GitHub release · GitHub Wiki guide. Contact and support: open a Discussion at patchvault-81y.pages.dev.
Last Updated:
FAQ
Is the request npm package deprecated?
Yes. Every request version on npm carries the notice "request has been deprecated, see https://github.com/request/request/issues/3142", and request-promise, request-promise-native and request-promise-any are deprecated "because they extend the now deprecated request package". request still gets about 15 million downloads a week, mostly through old code and transitive dependencies.
Is there a security issue with request?
Yes. GHSA-p8p7-x288-28g6 (CVE-2023-28155) is an SSRF via cross-protocol redirects that affects request <= 2.88.2, and there is no patched version. The fix is to stop depending on request.
What replaces request in Node.js?
The built-in global fetch, based on undici. It has been on by default since Node 18.0.0 and stable since Node 21.0.0, with no dependency to install. For proxies, custom TLS or connection pools you pass an undici dispatcher (Agent, ProxyAgent, EnvHttpProxyAgent).
Is there an official request → fetch codemod?
No. The official Node.js codemods (nodejs/userland-migrations) have an axios → fetch recipe but no request recipe (checked Oct 30, 2026). The only community codemod we found (request-to-fetch 0.1.0) rewrites call sites with jscodeshift and Babel.
Why not just rewrite every request() call to await fetch()?
Because request is callback-based and fetch returns a Promise. A rewrite has to turn callbacks into async code, and request differs from fetch in many quiet ways: non-2xx is not an error, json:true parses and sets headers, POST redirects are not followed, a slow server gives ESOCKETTIMEDOUT, redirects change POST to GET and drop the body, and request-promise rejects 4xx/5xx.
The pack keeps your call sites byte-identical. It repoints only the import at a generated fetch shim with request's semantics, and only when every call in the file is in the supported subset. Parity is tested against the real request 2.88.2.
What does the codemod not touch?
Streams (.pipe()), form / formData uploads, cookie jars, auth, agentOptions / TLS, proxies, request.defaults(), options built elsewhere, and request-promise transforms. Each one gets a precise finding with a native-fetch recipe and source link, and one unsafe call keeps the whole file unchanged.
Does fetch respect HTTP_PROXY like request did?
Not by default. request read HTTP_PROXY, HTTPS_PROXY and NO_PROXY automatically. With fetch, set undici's EnvHttpProxyAgent as the global dispatcher, or on Node 24+ start with NODE_USE_ENV_PROXY=1. The checker warns about this for every project that drops request.
Is my code uploaded anywhere?
No. This free checker runs entirely in your browser. The paid pack is a zero-dependency Node.js CLI that runs locally on your repo.
How do I get the pack after paying?
Instantly. After checkout, Stripe redirects you to your private download page, and the unlock key is in the link. Save the link: it is your copy.
More migration packs
@vercel/kv & @vercel/postgres → Upstash + Neon
Free checker and codemod for the deprecated Vercel storage SDKs, keeping{ rows } working.