Going through ES2025 and ES2026 properly for once
I finally read the ES2025 list properly, Temporal shipped in Chrome and ES2026 is close. What's in my code now and what still has to wait.

Every June a new ECMAScript edition gets approved, and every June I skim the list, think "nice", and go back to writing exactly the same code as before. This year I sat down with it on a quiet Sunday and went through it feature by feature, partly because a surprising amount of it is stuff I've been pulling in from npm (or copying between repos) for years, and partly because Temporal finally shipped in Chrome and I wanted to know where I stood before someone at work asked me.
So this is my pass over it, in roughly the order I'd care about each thing, with a note on whether it's in code I actually ship.
ES2025
ES2025 was approved last June. Every current browser has most of it, and so does Node 22 and up.
The one I've used most is iterator helpers. They're the array methods you already know (filter, map, take, drop, flatMap, reduce, some, every, find) but on any iterator, and lazy:
const firstTenIds = rows
.values()
.filter((r) => r.active)
.map((r) => r.id)
.take(10)
.toArray();
Nothing gets built in the middle. With a generator or a big Map, each step pulls one item at a time, and take(10) stops the whole chain once it has ten. There's also Iterator.from() to wrap anything iterable. Most of my use is on Map.prototype.values() and generators in Node scripts, where I used to spread everything into an array just so I could call .filter on it, which always felt a bit silly for something with a few hundred thousand entries.
Then the Set methods, which I've wanted for about as long as I've written JavaScript:
const before = new Set(["n12", "n3", "n2"]);
const after = new Set(["n12", "n20"]);
after.difference(before); // Set { "n20" } added
before.difference(after); // Set { "n3", "n2" } removed
before.intersection(after); // Set { "n12" }
before.isSubsetOf(after); // false
There's union, intersection, difference, symmetricDifference, isSubsetOf, isSupersetOf and isDisjointFrom. I had a little setDiff helper that had been copied into several repos over the years, slightly different in each one. It's gone now, and these are in pretty much everything I write. If you only pick one thing from this post, pick these.
Promise.try is smaller. It runs a function and hands you a promise whether the function was sync, async, or threw before it got going:
const result = await Promise.try(() => parseConfig(input));
Before, a synchronous throw in the set-up of a promise chain could escape the chain entirely, and you'd find out from an unhandled error somewhere else. I use it in one retry helper where the callbacks can be either kind, and that's about it.
RegExp.escape is the one that fixes a real bug class:
const pattern = new RegExp(`^${RegExp.escape(userInput)}$`, "i");
I've seen hand-rolled escape functions miss a character more than once. Any search box that builds a regex from what someone typed wants this. In my case it replaced a regex whose whole job was escaping other regexes, which is the kind of line nobody wants to review and everyone approves anyway.
And JSON modules with import attributes:
import config from "./config.json" with { type: "json" };
The with { type: "json" } bit isn't decoration. It tells the runtime what it's allowed to load, so a server can't hand you JavaScript when you asked for JSON. I use it in Node scripts. In app code nothing changes, because bundlers have handled JSON imports for as long as I can remember.
ES2025 also has Float16Array, RegExp modifiers and duplicate named capture groups. I haven't needed any of them yet, and I'm not going to pretend I have.
Temporal
This is the big one. Temporal replaces Date, and it's been "nearly ready" for roughly as long as I've been working.
Firefox shipped it last year. Chrome shipped it in Chrome 144 in January. And this month it reached Stage 4 at TC39, so it goes into ES2026.
const now = Temporal.Now.zonedDateTimeISO("Europe/London");
const meeting = now.add({ days: 1 }).with({ hour: 9, minute: 30 });
meeting.toString();
// 2026-03-16T09:30:00+00:00[Europe/London]
const d = Temporal.PlainDate.from("2026-03-29");
d.add({ months: 1 }).toString(); // "2026-04-29"
Values are immutable, months start at 1 like a normal person would expect, and time zones are real objects instead of something you hope the server got right. It also has separate types for a date with no time (PlainDate), a wall-clock time in a particular place (ZonedDateTime), and an exact moment (Instant). Date never let you say which of those you meant, and I think most date bugs I've seen come from exactly that.
My day job involves a lot of energy market data, which is all half-hourly settlement periods in UK time. The clocks go forward on 29 March this year, which gives you a 46-period day, and when they go back in October you get a 50-period day. Every one of those has been a bug at some point in some codebase I've worked on (sometimes the same bug, fixed twice, in two places). Temporal gets them right by default, because it does the arithmetic in the time zone you gave it.
Am I using it? Not in the browser yet. Safari doesn't have it, and our users are on whatever browser their IT department installed. I'm using the polyfill in one internal tool to get used to the API, and for new date logic I write it the Temporal way, so the switch later is mostly deleting an import.
ES2026, nearly
ES2026 should be approved in June. These are at Stage 4 already or close enough that I'd be surprised if they moved.
using is explicit resource management. Something gets cleaned up when it goes out of scope:
{
await using db = await openConnection();
const rows = await db.query("select 1");
} // db[Symbol.asyncDispose]() runs here, even if query throws
It's try/finally without the nesting, and it's handy for file handles, locks and test fixtures. I use it in Node 24 scripts. Not in browser code yet.
Math.sumPrecise adds up numbers without the floating point error piling up as it goes:
[0.1, 0.2, 0.3].reduce((a, b) => a + b); // 0.6000000000000001
Math.sumPrecise([0.1, 0.2, 0.3]); // 0.6
It isn't decimal maths, but for totals on a dashboard it's what you wanted all along. I'm not using it yet, and for money we already store integer pence, so it matters less to me than it might to you.
Map.getOrInsert does the "check, set a default, return it" dance in one call, and getOrInsertComputed takes a callback so the default is only built when it's needed:
const byArea = new Map();
for (const home of homes) {
byArea.getOrInsert(home.postcode, []).push(home);
}
Too new for me to rely on yet, but I can already think of a few places it'll tidy up.
Error.isError(x) tells you whether something really is an Error, even across realms (iframes, vm contexts) where instanceof gives you the wrong answer. That's mostly useful in logging and error-reporting code. And Uint8Array gets fromBase64(), toBase64(), fromHex() and toHex(), which replace the btoa/atob workarounds that only ever worked on "binary strings" and fell over on anything outside Latin-1:
const bytes = Uint8Array.fromBase64(payload);
const hex = bytes.toHex();
I'm using the base64 ones in a small secrets tool where the key lives in the URL fragment. Error.isError I haven't reached for yet.
How I decide what to use
At work the rule is dull and it works: if a feature is Baseline "widely available", or the code only runs in Node, use it. If it's only "newly available", use it behind a polyfill or where we control the browser. Anything else waits.
Side projects get a looser rule, because the worst case is that I break my own site and fix it on a Sunday.
Checking Baseline on MDN takes about ten seconds, and it has stopped me shipping something Safari didn't support more than once. I'd check it before reaching for anything on this list.
First published on my blog. Cover photo: Uoaei1, CC BY-SA 4.0, via Wikimedia Commons (source).
About the author
- Full stack engineer in London with 5+ years on production web platforms. I lead AI-assisted modernisation at Xanda: React and Go for the UK energy market, a government claims portal, and moving old Java and C++ systems onto the cloud. Outside work I run a small home server behind a Cloudflare Tunnel with a handful of public tools on it: Doorstep (rental alerts across Rightmove, OnTheMarket and OpenRent), SeenSooner (NHS A&E and planned-care waits), GridPulse (live GB grid carbon), Sift (LLM ticket triage that survives model failures) and AI Radar (a news digest written hourly by an n8n workflow). I write here about React and Next.js upgrades, Node, coding with AI agents, and the CVEs I've had to patch. Originals live at blogs.kishankanejiiya.tech.
Comments
Join the discussionNo comments yet. Be the first to comment.




