The JavaScript stack we would set up today
What to install in 2026, and the long list of packages the language quietly made redundant.
JavaScript's toolchain problem was never a lack of options. It was that the correct answer changed every eighteen months. It has been stable for a while now, which makes this a good moment to delete things.
The core#
Node LTS with pnpm. pnpm's strict node_modules layout catches phantom dependencies — packages you use but never declared — which is a real class of bug that npm allows through silently.
ESLint with type-aware rules, even without TypeScript. Add a jsconfig.json with checkJs: true and you unlock no-floating-promises, which is the highest-value lint rule in the language and the one that catches the most common bug in generated JavaScript. The full config is in the failure modes.
Vitest. Fast, ESM-native, no configuration for the common case.
A formatter. Prettier if your team already knows it, Biome if you want one fast tool for formatting and basic linting. Not both.
Consider TypeScript, even if you do not write it#
You can get most of the type checking without changing a single file extension:
{ "compilerOptions": { "checkJs": true, "strict": true, "noEmit": true } }/**
* @param {string} id
* @returns {Promise<User>}
*/
export async function getUser(id) { }JSDoc types are checked by tsc and by your editor. For a codebase where a full migration is not on the table, this is a large fraction of the benefit for a very small fraction of the cost — and it makes the type-aware lint rules work.
Or go all the way:
Hosting#
App Platform detects a Node project and deploys it. For anything that can run at the edge, Cloudflare Workers' free tier is excellent and earns us nothing.
The delete list#
This is the most useful section on the page. Every one of these is still routinely generated, because the training data predates the replacement.
| Package | Replaced by |
|---|---|
axios | fetch — stable in Node since 18 |
moment, date-fns for basics | Intl.DateTimeFormat, Temporal |
lodash | Object.groupBy, Array.at, structuredClone, toSorted, ?., ?? |
uuid | crypto.randomUUID() |
dotenv | node --env-file=.env |
rimraf, mkdirp | fs.rm / fs.mkdir with { recursive: true } |
node-fetch | global fetch |
chalk (simple cases) | util.styleText |
glob (simple cases) | fs.glob |
JSON.parse(JSON.stringify(x)) | structuredClone(x) |
is-odd and friends | please |
Put the top half of that table in your AGENTS.md. It stops the drift at source.
What to skip#
- A framework for a script. If it is under 200 lines, it is a file.
- A bundler for a Node server. Only worth it for cold-start-sensitive serverless.
- Two testing libraries. You will end up with both and use neither properly.
- Micro-dependencies. Every one is a supply-chain surface. The stdlib got good; check it first.
Learning#
Text-first, skimmable, good for filling one specific gap rather than watching eight hours of video.
For depth on the runtime — event loop, streams, performance — the books still beat everything online.
Common questions#
Should I migrate to TypeScript?#
If the codebase is small or new, yes. If it is large, start with checkJs and JSDoc types — you get the type-aware lint rules and most of the editor benefit without a migration project, and you can convert file by file afterwards if it proves worth it.
Bun or Node?#
Node for anything you need to be boring. Bun is genuinely fast and genuinely pleasant, and the compatibility gaps you will hit are unpredictable rather than frequent — which is the worst shape of problem to hit in production.
npm, pnpm or yarn?#
pnpm. Faster, less disk, and the strict layout catches undeclared dependencies. npm is fine and universal. Yarn only if you are already on it and it works.
Get the JavaScript agent pack
A battle-tested AGENTS.md, the review checklist, and the failure-mode cheat sheet for JavaScript. One email, then occasional updates when the tooling shifts. No course pitch.
AGENTS.md now — no email needed.
Disclosure: some links on this page are affiliate links. If you buy something through one, we earn a commission at no extra cost to you. We only list tools we would tell a friend to use, and we say so when we have not used something ourselves. This is how the site stays free and ad-light.