Skip to content
👉All tips here

JavaScript’s Biggest Update in Years: What ES2027 Actually Changes

ES2027 JavaScript features — Temporal date example

Why ES2027 JavaScript Features Matter

That’s the kind of trap Date has been setting for 25+ years, and it’s exactly what the ES2027 JavaScript features below are designed to fix.

new Date("0") and new Date(0) look like they should be the same thing. They’re not. The string version gives you the year 2000, that’s just how JavaScript’s date parser interprets a lone "0". The number version correctly gives you the Unix epoch: January 1st, 1970.

Try to compare them with Date.parse , and it gets worse because that function only accepts strings, so it silently converts the number 0 into the string "0" first. Now both say the year 2000.

That’s the kind of trap Date has been setting for 25+ years. Temporal is TC39’s fix, and it’s one of four features locked in for ES2027 alongside a handful of Stage 2/3 proposals close behind, including one that could give every JS framework a shared reactivity core.

1. Temporal – a real date/time API

Reached Stage 4 in March 2027. Temporal is a namespace containing several classes, each built to do one job properly instead of one Date object doing every job poorly:

Why it matters, the DST bug every date library gets wrong:

const departure = Temporal.ZonedDateTime.from(
  "2027-10-24T20:00:00[America/New_York]"
);
const arrival = departure
  .add({ hours: 7 })
  .withTimeZone("Europe/London");

console.log(arrival.toString());
// 07:00 the next morning — not 08:00

A 7-hour flight leaving 8 PM New York time should land around 3 AM New York / 8 AM London. But the clocks go back in London that night, so it actually lands at 7 AM – and Temporal knows this without being told. You can confirm the exact shift with getTimeZoneTransition().

The same logic protects you the other way: push an 11 AM meeting forward “one day” across a DST change, and Temporal keeps it at 11 AM, because you asked for a day, not a fixed number of hours.

Every Temporal object is also immutable – operations return new objects, so nothing changes underneath you, and months are zero-indexed for consistency with the rest of the API. Similar to how Error.cause preserves the original error instead of letting it get mutated away by wrapping.

Support today: Firefox, Chrome, Node.js, Deno. Bun is coming soon; Safari is behind.

Docs: MDN – Temporal

2. using – explicit resource management

Also Stage 4 (May 2027), and already shipping in Firefox, Chrome, Node, Bun, and Deno for a while that you may have used it already.

Anytime you open something that needs closing a file handle, a DB connection, a stream- you’d normally reach for try/finally and hope you didn’t forget it somewhere. using does it for you: when the variable goes out of scope (end of block, early return, or a thrown exception), JavaScript automatically calls [Symbol.dispose]().

{
  using file = openFile("data.txt");
  // ... do stuff with file
} // file's [Symbol.dispose]() runs automatically here

There’s also await using for async cleanup ([Symbol.asyncDispose]()), and DisposableStack for composing several resources so they tear down in reverse order.

Docs: MDN – using declarations

3. Iterator.zip – combine iterables in parallel

Still experimental, only shipping in Firefox 148 so far. Say you have three separate arrays with names, ages, cities, and want to walk them together:

const combined = Iterator.zip([names, ages, cities]);
// each iteration yields: [name, age, city]

Iterator.zipKeyed does the same thing but gives you named objects instead of arrays. Both accept a mode option:

  • "shortest" (default) – stop when the shortest input runs out
  • "longest" – keep going until the longest finishes, with optional padding values for the gaps
  • "strict" – throw if the inputs aren’t the same length

This continues the iterator-helpers work from ES2025 (map, filter, take, drop), slowly closing the gap that once meant reaching for Lodash.

Docs: MDN – Iterator.zip()

4. Atomics.pause — a hint for spin-locks

The low-level one. If you’re not writing multi-threaded code against a SharedArrayBuffer, you’ll probably never touch this. When a thread is busy-waiting in a tight loop for a lock to release, Atomics.pause() tells the CPU “I’m intentionally spinning” so it can handle that loop more efficiently instead of hammering the core.

const sab = new SharedArrayBuffer(1024);
const i32 = new Int32Array(sab);

let spin = 0;
do {
  if (Atomics.compareExchange(i32, 0, 0, 1) === 0) break;
  Atomics.pause();
  spin++;
} while (spin < 10);

Mostly relevant to library authors and performance-critical code. Supported in most browsers, Bun, Deno, and reportedly Node too.

Docs: MDN – Atomics.pause()

More ES2027 JavaScript Features on the Way

  • import defer is a module code that doesn’t run until you actually use it for the first time, unlike dynamic import(), which still runs top-level code once fetched. Good for startup time in apps with large dependency graphs.
  • Promise.allKeyed – like Promise.all, but instead of destructuring an array by position, you pass an object and get named results back. Currently Stage 2 (2.7), not Stage 3 yet, and still one step from candidate status. Spec repo
  • Decorators – genuinely Stage 3 since 2022, and Bun shipped standard decorators in February 2027. Still an open question when this reaches Stage 4. Spec repo

Stage 1 is the one to watch

Signals – a built-in reactive primitive (writable values, computed values, automatic dependency tracking) designed to give Angular, Vue, Svelte, and Solid a shared low-level foundation, rather than each maintaining its own reactivity system. Very early, but arguably the highest-impact proposal on this list if it lands. Spec repo

That’s the full rundown of confirmed ES2027 JavaScript features, plus a few Stage 2 and Stage 3 proposals worth keeping an eye on.