The error, verbatim
Jump to the fix ↓(node:24108) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
Tested on
- Node
- 20.20.2, 22.23.4, 24.22.1, 26.13.0 (Linux); 24.14.0, 26.11.1 (Windows)
- Packages
- node-fetch 2.7.0, whatwg-url 5.0.0, tr46 0.0.3 / 5.1.1, tough-cookie 4.1.4, psl 1.15.0, ajv 6.15.0
- Bundler
- esbuild 0.28
- OS
- Ubuntu on GitHub Actions; Windows 11 Pro
✓ Last re-run on GitHub Actions · see the run · all repros
Two things decide whether you see this warning, and neither is your code: the Node version and whether you bundle. On Node 20 it never appeared, even for a direct require('punycode'). On Node 22, 24 and 26 it appeared for code outside node_modules, which includes anything a bundler copied into your build, and that’s why it shows up in production logs but not in development. It’s only a warning, and the program keeps running.
The odd part is when you see it. On Node 24.14.0:
| What ran | Warning? |
|---|---|
Your own code calling require('punycode') |
Yes |
node-fetch 2 from node_modules, actually fetching |
No |
The same code bundled into dist/app.js with esbuild |
Yes |
Node only prints it for code outside node_modules. A package that loads punycode stays quiet in development, then the warning appears once a bundler copies that package into your build output. That’s why it so often shows up in production logs, serverless functions and CLI builds, from code you never wrote. Unbundled node-fetch 2 stayed silent on Node 26.11.1 as well.
Which Node versions print it
| Node 20.20.2 | Node 22.23.4 | Node 24.22.1 | Node 26.13.0 | |
|---|---|---|---|---|
Your own require('punycode') |
no warning | warning | warning | warning |
node-fetch 2 bundled with esbuild |
no warning | warning | warning | warning |
node-fetch 2 from node_modules |
no warning | no warning | no warning | no warning |
So the warning usually appears right after moving from Node 20 to 22 or newer, with no change to your code. Node 20 loads the same module silently.
Which packages cause it
I bundled each of these on its own and ran the result on Node 22, 24 and 26:
| Package | Bundled: DEP0040? |
|---|---|
node-fetch 2.7.0 |
yes |
whatwg-url 5.0.0 (used by node-fetch 2) |
yes |
tough-cookie 4.1.4 |
no |
psl 1.15.0 |
no |
ajv 6.15.0 (through uri-js) |
no |
The last three use the punycode package from npm, which npm ls punycode lists, rather than Node’s built-in module, so they’re not the cause even though the name matches. Their bundles contained no require("punycode") of the built-in at all; the node-fetch 2 and whatwg-url 5 bundles each contained two.
Find the package
--trace-deprecation isn’t much help here: the stack starts at node:punycode:7:10, inside Node, not in your code.
The usual source is node-fetch 2, through whatwg-url 5 and tr46 0.0.3. Check whether you have it:
npm ls tr46 whatwg-url`-- node-fetch@2.7.0
`-- whatwg-url@5.0.0
`-- tr46@0.0.3If that chain shows up, node-fetch 2 is the one, either yours or a dependency’s (older SDKs often use it).
The fix: stop using node-fetch 2
Node 18 and later have fetch built in. Remove node-fetch and use the global one:
const res = await fetch('https://registry.npmjs.org/is-number');If the code needs the node-fetch API, node-fetch 3 is ES-module only and doesn’t use whatwg-url 5. It fetched fine on Node 24 (status 200). If a dependency pulls in node-fetch 2, update that dependency.
What didn’t work
node --no-deprecation hides every deprecation warning, this one included. It changes nothing about the code, and it also hides the next warning you’d want to see.
How this was tested
Windows 11 Pro, Node 24.14.0 and 26.11.1, October 18, 2026. A one-line script fetching from the npm registry with node-fetch 2.7.0, run directly and as an esbuild 0.28.2 bundle (--bundle --platform=node), then with a tr46 override, a punycode alias, node-fetch 3 and native fetch. Every message above is the real output.
November 1, 2026: own-code, unbundled and esbuild-bundled runs on Node 20.20.2, 22.23.4, 24.22.1 and 26.13.0 on GitHub Actions ubuntu-latest, for node-fetch 2.7.0, whatwg-url 5.0.0, tough-cookie 4.1.4, psl 1.15.0 and ajv 6.15.0. The script and the full output are public.
— N.K., end of entry No.076