NodeJSES6+ Features You Need

ES6+ Features You Need

Modern Node.js runs a current V8, so the latest JavaScript is available with no transpiler. Beyond async/await, a handful of ES2015+ features appear in virtually every codebase. This page is a server-focused quick reference to the ones you will use daily — with the sharp edges flagged.

Default, rest & spread parameters

JS
function createServer(port = 3000, { https = false } = {}) {
  // 'port' defaults to 3000; the options object itself defaults to {}
  // so createServer() with no args does not throw
}

function sum(...nums) {                 // rest: gather args into a real array
  return nums.reduce((t, n) => t + n, 0)
}
sum(1, 2, 3, 4)                          // 10

const base = [1, 2]
const more = [...base, 3, 4]             // spread: [1,2,3,4]
Why `= {}` on the options object matters
Without the `= {}` default, calling `createServer(3000)` would try to destructure `undefined` and throw `Cannot destructure property 'https' of undefined`. The `= {}` makes the whole options argument optional — a standard pattern for configurable functions.
Destructuring everywhere

JS
// In imports
const { readFile, writeFile } = require('node:fs/promises')

// In function parameters (great for "options objects")
function connect({ host, port = 5432, ssl = true }) { /* ... */ }

// Nested, with renaming and defaults
const { data: { items = [] } = {} } = response
Spread/rest are shallow
`{ ...obj }` and `[...arr]` copy only the top level — nested objects and arrays remain shared by reference. For an independent deep copy, use the global `structuredClone(obj)` rather than spread or `JSON.parse(JSON.stringify(...))` (which loses Dates, Maps, and functions).
Classes

JS
class HttpError extends Error {
  constructor(status, message) {
    super(message)
    this.status = status
    this.name = 'HttpError'
  }
}

throw new HttpError(404, 'Not Found')
Private fields and static blocks
Modern Node supports true private class fields with the `#` prefix — `#secret` is genuinely inaccessible outside the class, enforced by the runtime (not a convention like `_secret`). There are also `static` fields and `static {}` initializer blocks for class-level setup.
Modules (import / export)

JS
// math.mjs
export const add = (a, b) => a + b
export default function multiply(a, b) { return a * b }

// app.mjs
import multiply, { add } from './math.mjs'

Node supports both ES Modules and CommonJS — a distinction important enough to get its own pages: ES Modules and CommonJS vs ES Modules.

Map, Set & for...of

JS
const seen = new Set()           // unique values, any type
seen.add('a'); seen.has('a')     // true

const cache = new Map()          // any key type, preserves insertion order
cache.set('user:1', { name: 'Ada' })
cache.get('user:1')

for (const value of [10, 20, 30]) console.log(value)

Use case

Reach for

Why not a plain object

Keyed lookup with non-string keys

Map

Object keys are coerced to strings

Frequent add/delete by key

Map

Map is optimized for it; preserves order

Membership / de-duplication

Set

O(1) has, no value storage needed

Keys you fear collide with __proto__

Map

Objects inherit prototype keys; Map does not

Optional chaining & nullish coalescing

JS
const city = order?.customer?.address?.city ?? 'N/A'
const limit = options.limit ?? 100   // only defaults on null/undefined, not 0
Other gems
  • Template literals — string interpolation with ${...} and multi-line strings.

  • Object shorthand{ name, age } instead of { name: name, age: age }.

  • Computed keys{ [dynamicKey]: value }.

  • Array methodsflat, flatMap, and at(-1) for the last element.

  • Object.entries / fromEntries — convert objects ↔ key/value pairs.

  • Logical assignmenta ??= b, a ||= b, a &&= b.

  • Numeric separators1_000_000 for readable large numbers.

Refresher complete
You now have the language toolkit. Begin the core curriculum with the [Node.js Architecture Overview](/nodejs/architecture).