Chapter 2: Node.js Requirements
1. Which JavaScript version should you use with Node.js?
Short answer (2025–2026 reality):
Use modern JavaScript (ES2020 → ES2025 features) Most teams today use Node.js 18, 20 or 22 → all of them support almost everything you want.
Recommended minimum versions in 2026
| Node.js version | Release year | Recommended for | Modern JS support level | Status in 2026 |
|---|---|---|---|---|
| 18.x | 2022 | Legacy support only | Good (but missing some new things) | Maintenance only |
| 20.x | 2023 | Most common choice | Excellent | Active LTS |
| 22.x | 2024 | New projects, experiments | Almost everything | Current |
| 21.x | 2023 | Avoid | — | End-of-life |
Practical recommendation for most people in 2026:
Start with Node.js 20 LTS → Very stable, huge ecosystem compatibility, long support until April 2027
If you want newest syntax & performance → Node 22 is also perfectly fine.
2. Must-know modern JavaScript features you should use in Node.js
These features are expected in good Node.js code in 2025–2026.
| Feature | Example | Why you should use it | Available since |
|---|---|---|---|
| let / const | const user = { name: “Aman” } | Block scope, no hoisting bugs | ES6 |
| Arrow functions | users.map(u => u.name) | Cleaner, no this confusion in many cases | ES6 |
| Destructuring | const { name, email } = req.body | Much cleaner code | ES6 |
| Spread / Rest | const copy = { …user, active: true } | Immutable updates, clean merging | ES6 |
| Template literals | User ${name} joined |
Readable strings | ES6 |
| Optional chaining | user?.profile?.bio | Avoids “Cannot read property of undefined” errors | ES2020 |
| Nullish coalescing | const port = process.env.PORT ?? 3000 | Better default values than ` | |
| Logical assignment | config.timeout ??= 5000 | Clean defaults | ES2021 |
| Top-level await | const data = await fetchData() (outside async fn) | Cleaner startup scripts | Node 14+ |
| Private class fields | #secret = 42 | Real encapsulation | ES2022 |
| Array findLast / findLastIndex | items.findLast(x => x.active) | Very useful in logs, queues | ES2023 |
3. Most important decision: CommonJS vs ESM (2026 reality)
This is the biggest JavaScript decision you make when starting a Node.js project.
| Aspect | CommonJS (require) | ESM (import) | Winner in 2026 |
|---|---|---|---|
| Syntax | const express = require(‘express’) | import express from ‘express’ | ESM |
| File extension | .js | .js or .mjs | — |
| “type”: “module” | Not needed | Required in package.json | — |
| Dynamic import | require() can be anywhere | await import() only inside async functions | CommonJS wins |
| Top-level await | Not supported | Supported | ESM |
| Tree-shaking | Weak support | Much better | ESM |
| Ecosystem support 2026 | Still very good | Excellent (almost everything) | ESM |
| New libraries 2025+ | Often ESM-only | — | ESM |
| Node.js future | Slowly de-emphasized | The future direction | ESM |
Realistic recommendation in 2026
| Project type | Recommendation | Why? |
|---|---|---|
| Learning / small script | ESM | You learn modern JavaScript right away |
| New serious API / product | ESM | Future-proof, better tooling, most new libs are ESM |
| Maintaining old project (Express 4) | CommonJS | Less friction when mixing old packages |
| Library / npm package | ESM (with dual support) | Maximum compatibility + modern benefits |
How to start a new project with ESM (recommended)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// package.json { "name": "my-api", "type": "module", // ← this line is very important "main": "src/index.js", "scripts": { "start": "node src/index.js", "dev": "nodemon src/index.js" } } |
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// src/index.js import express from 'express'; import dotenv from 'dotenv'; dotenv.config(); const app = express(); app.use(express.json()); app.get('/', (req, res) => { res.json({ message: 'Hello from ESM Node.js' }); }); const PORT = process.env.PORT || 5000; app.listen(PORT, () => { console.log(`Server running → http://localhost:${PORT}`); }); |
4. JavaScript features you can mostly avoid in Node.js (2026)
These are either not needed or have better alternatives:
| Feature | Usually avoid in Node.js? | Reason / better alternative |
|---|---|---|
| var | Yes | let / const are safer |
| IIFE (Immediately Invoked) | Almost always | Top-level await + modules make it unnecessary |
| arguments object | Yes | Rest parameters …args are clearer |
| class prototype methods | Sometimes | Private fields #field + arrow methods are often cleaner |
| Callbacks (heavy use) | Yes | Prefer async/await + Promise |
5. Quick checklist – “Is my JavaScript modern enough for Node.js in 2026?”
Copy-paste and check your code:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[ ] Using `import` / `export` instead of `require` / `module.exports` [ ] Using `const` and `let` (almost never `var`) [ ] Using optional chaining `?.` and nullish coalescing `??` [ ] Using template literals instead of `"string" + variable` [ ] Using `async/await` instead of `.then().catch()` [ ] Destructuring objects and arrays frequently [ ] Using spread operator for copying / merging [ ] `"type": "module"` in package.json (if you chose ESM) [ ] Top-level await in entry files when it makes sense |
If most of these are yes → you’re writing modern Node.js JavaScript.
6. Summary table – JavaScript requirements at different levels
| Level | JavaScript style you should aim for | Node.js version | Module system |
|---|---|---|---|
| Absolute beginner | Modern syntax, but CommonJS is okay at first | 20 LTS | CommonJS or ESM |
| Intermediate | Full ESM, async/await, modern operators | 20 or 22 | ESM |
| Production / team | ESM + top-level await + Zod validation + structured logging | 20 LTS | ESM |
| Library author | Dual CommonJS + ESM support (exports map + conditional exports) | 20 or 22 | Both |
Would you like to go deeper into any of these topics next?
Examples:
- How to convert an old CommonJS project to ESM step-by-step
- How to write dual CommonJS + ESM packages (very useful for libraries)
- Real example project using only modern JS features
- Common mistakes people make when switching to ESM
- Using top-level await in real startup code
- Recommended ESLint + Prettier setup for modern Node.js
Just tell me which direction you want — I’ll continue with detailed examples. 😄
