ES2026 Complete Guide: All New JavaScript Features Explained
Guide · Updated May 2026

ES2026 Complete Guide:
All New JavaScript Features Explained

ECMAScript 2026 is one of the biggest JavaScript updates in years. From automatic resource cleanup to pattern matching — here's everything you need to know with real code examples.

Oleg Maximov May 16, 2026 14 min read

Introduction

Every June, TC39 — the technical committee that standardizes JavaScript — publishes a new edition of the ECMAScript specification. ES2026 (ECMAScript 2026) is shaping up to be one of the most significant updates in recent memory, delivering features that JavaScript developers have been requesting for years.

This year's edition introduces practical, day-to-day improvements: automatic resource cleanup with using, precise math with Math.sumPrecise(), better error-handling tools, and several Stage 3 proposals like Pattern Matching and the Pipeline Operator that are nearing completion. Meanwhile, the long-awaited Temporal API — a complete replacement for the infamous Date object — has reached Stage 4 and is slated for ES2027.

In this guide, I'll walk through every significant feature landing in ES2026 and the proposals you should start learning today. You'll find real code examples, adoption status, browser support notes, and practical advice on when to use each feature.

1. Explicit Resource Management: using and await using

Stage 4 The single most impactful feature landing in ES2026 is explicit resource management. If you've ever written try { ... } finally { resource.close(); }, this feature eliminates that boilerplate entirely.

How using Works

The using keyword declares a block-scoped variable whose Symbol.dispose method is automatically called when the variable goes out of scope — similar to Python's with statement or C#'s using:

// Before ES2026 — manual cleanup
function readConfig(path) {
  const file = fs.openSync(path, 'r');
  try {
    return JSON.parse(fs.readFileSync(file, 'utf-8'));
  } finally {
    fs.closeSync(file);
  }
}

// With ES2026 — automatic cleanup
function readConfig(path) {
  using file = fs.openSync(path, 'r');
  return JSON.parse(fs.readFileSync(file, 'utf-8'));
  // file is automatically closed when scope exits
}

Async Resources with await using

For asynchronous resources like database connections or file streams, use await using with Symbol.asyncDispose:

class DatabaseConnection {
  async [Symbol.asyncDispose]() {
    await this.close();
    console.log('Connection closed');
  }

  async query(sql) { /* … */ }
}

async function getUser(userId) {
  await using db = new DatabaseConnection(config);
  return db.query(`SELECT * FROM users WHERE id = ${userId}`);
  // db.close() is called automatically
}

Why This Matters

Resource leaks are one of the most common bugs in production JavaScript applications. File handles, database connections, and network sockets that aren't properly cleaned up cause memory leaks and connection pool exhaustion. using eliminates an entire category of bugs by making resource disposal automatic and deterministic.

Node.js 24+ and Chrome 126+ already support using natively. For older environments, Babel provides a transform plugin that's included in @babel/preset-env with the es2026 target.

2. Math.sumPrecise() — Floating Point Precision

Stage 4 Every JavaScript developer has encountered floating-point arithmetic quirks:

0.1 + 0.2; // 0.30000000000000004 (not 0.3!)

Math.sumPrecise() introduces a compensated summation algorithm (Kahan-Babuška-Neumaier) that significantly reduces accumulation errors when summing arrays of floating-point numbers:

const prices = [0.1, 0.2, 0.3, 0.4];

// Traditional approach — accumulates errors
const naiveSum = prices.reduce((a, b) => a + b, 0);
// 0.1 + 0.2 + 0.3 + 0.4 = 1.0000000000000002

// ES2026 — precise summation
const preciseSum = Math.sumPrecise(prices);
// 0.0 + 0.1 + 0.2 + 0.3 + 0.4 = 1.0 (exact!)

This is a game-changer for financial calculations, statistical operations, and scientific computing in JavaScript. While it doesn't replace BigInt for exact integer arithmetic, it significantly improves precision for real-world floating-point scenarios.

Math.sumPrecise() accepts any iterable — arrays, Sets, typed arrays, or generator output — and returns 0 for empty iterables.

3. Error.isError() — Reliable Error Type Checking

Stage 4 Checking whether a value is an Error instance has been surprisingly tricky in JavaScript due to cross-realm issues (errors thrown in iframes or across worker boundaries don't pass instanceof Error):

// Old approach — unreliable
try {
  await riskyOperation();
} catch (err) {
  if (err instanceof Error) { // fails across realms!
    console.error(err.message);
  }
  // Fallback: duck-typing
  if (err && typeof err.message === 'string') {
    console.error(err.message);
  }
}

// ES2026 — reliable
try {
  await riskyOperation();
} catch (err) {
  if (Error.isError(err)) {
    console.error(err.message);
    console.error(err.stack);
  }
}

Error.isError() works reliably across realm boundaries (iframes, workers, VM contexts) and correctly identifies native Error instances, including subclasses like TypeError, RangeError, and SyntaxError. It returns false for plain objects that happen to have message and stack properties.

4. Pattern Matching — A New Way to Write Conditionals

Stage 3 Pattern Matching is arguably the most anticipated JavaScript feature in years. It introduces a match expression that lets you destructure and test values against patterns in a declarative way — similar to Rust's match or Haskell's pattern matching:

// Before — nested if-else or switch
function getShapeArea(shape) {
  if (shape.type === 'circle') {
    return Math.PI * shape.radius ** 2;
  } else if (shape.type === 'rectangle') {
    return shape.width * shape.height;
  } else if (shape.type === 'triangle') {
    return (shape.base * shape.height) / 2;
  }
  throw new Error('Unknown shape');
}

// With Pattern Matching
function getShapeArea(shape) {
  return match (shape) {
    { type: 'circle', radius } => Math.PI * radius ** 2,
    { type: 'rectangle', width, height } => width * height,
    { type: 'triangle', base, height } => (base * height) / 2,
    _ => throw new Error('Unknown shape'),
  };
}

Key Pattern Types

ES2026 Pattern Matching supports several pattern kinds:

// Practical example: handling API responses
function handleResponse(response) {
  return match (response) {
    { status: 200, data } => renderSuccess(data),
    { status: 201, data } => renderSuccess(data),
    { status: 204 } => renderDeleted(),
    { status: 400, error } => renderBadRequest(error),
    { status: 401 } => redirectToLogin(),
    { status: 403 } => renderForbidden(),
    { status: 404 } => renderNotFound(),
    { status: 500, error } => renderServerError(error),
    _ => renderUnknownError(),
  };
}

Pattern Matching is at Stage 3, meaning the API is mostly stable but may see minor changes before finalization. You can experiment with it today using the Babel plugin @babel/plugin-proposal-pattern-matching. V8 and SpiderMonkey have published early implementation work.

5. Pipeline Operator |> — Readable Function Composition

Stage 3 The Pipeline Operator introduces a clean, left-to-right syntax for chaining function calls. Instead of reading deeply nested expressions inside-out:

// Before — deeply nested, hard to read
const result = formatCurrency(
  applyDiscount(
    calculateTotal(
      getCartItems(userId)
    ),
    promoCode
  ),
  'USD'
);

// With Pipeline Operator — reads top-to-bottom
const result = getCartItems(userId)
  |> calculateTotal(%)
  |> applyDiscount(%, promoCode)
  |> formatCurrency(%, 'USD');

The |> operator pipes the value on its left into the function on its right. The topic token (%) refers to the piped value — you can use it multiple times, nest it in deeper expressions, or omit it entirely for unary function calls:

// Unary function — topic is implicit
users
  |> filterActive
  |> sortByDate
  |> toJSON

// Multiple arguments — use topic token
users
  |> filterActive(%)
  |> sortByDate(%, 'desc')
  |> mapToNames(%)

// Nested expressions
fetch('/api/data')
  |> await %
  |> %.json()
  |> console.log

The Pipeline Operator is one of the most intensely debated proposals in TC39 history — multiple competing syntax versions were proposed and vetted over several years. The current proposal (Hack pipes) won consensus in late 2025 and is rapidly progressing toward Stage 4.

6. Import Defer — Lazy Module Evaluation

Stage 3 import defer allows you to defer the evaluation of a module until it's actually used, improving startup performance:

// Normal import — evaluated eagerly
import { heavyLibrary } from './heavy-library.js';

// Deferred import — evaluated on first use
import defer { markdownParser } from './markdown-parser.js';

function renderPage(content) {
  // The markdown-parser module is only loaded here,
  // on the first call to renderPage
  return markdownParser.parse(content);
}

This is particularly valuable for large applications where many modules are imported at the top level but only used conditionally. import defer lets you keep imports at the top of your file (maintaining readability and static analysis benefits) without paying the cost of evaluating modules that may never be used on a given page.

Note the difference from import() — dynamic imports are evaluated asynchronously and at runtime, while import defer is a static declaration that defers evaluation but preserves the module's static structure for tree-shaking and bundler analysis.

7. Temporal API — JavaScript's Date Is Finally Fixed

Stage 4 Slated for ES2027 While not quite making it into ES2026, the Temporal API deserves a special mention because it's the most significant JavaScript language addition in a decade and it reached Stage 4 in March 2026. If you're planning a new project, you should start using Temporal today.

JavaScript's Date object has been a source of bugs and frustration since the language's inception. It's mutable, has no timezone support (the timezone is always local), has inconsistent parsing, and uses zero-indexed months. Temporal fixes all of this:

// Date — painful and error-prone
const d = new Date(2026, 4, 16); // May 16 — wait, months are 0-indexed!
d.setMonth(5); // Mutates the original — surprise!
console.log(d.toISOString()); // Assumes UTC, but gets parsed as local

// Temporal — explicit and correct
const date = Temporal.PlainDate.from({ year: 2026, month: 5, day: 16 });
// => 2026-05-16 (clear, no index confusion)
const zoned = Temporal.ZonedDateTime.from({
  timeZone: 'Europe/Minsk',
  year: 2026,
  month: 5,
  day: 16,
  hour: 10,
  minute: 0,
});
// => 2026-05-16T10:00:00+03:00[Europe/Minsk]

// Immutable operations
const nextMonth = date.add({ months: 1 });
// date is unchanged — nextMonth is a new instance

// Timezone-aware arithmetic
const now = Temporal.Now.zonedDateTimeISO('America/New_York');
const inMinsk = now.withTimeZone('Europe/Minsk');
const duration = now.until(inMinsk); // Time difference with timezone awareness

Temporal Key Types

You can use the official Temporal polyfill today in Node.js and all modern browsers. Node.js 24+ ships Temporal behind the --experimental-temporal flag, and full native support is expected in Node.js 26+.

Feature Summary Table

Feature Stage ES Version Status
Explicit Resource Mgmt (using) Stage 4 ES2026 Node 24+, Chrome 126+, Babel
Math.sumPrecise() Stage 4 ES2026 Node 24+, Chrome 127+, polyfill
Error.isError() Stage 4 ES2026 Node 24+, polyfill
Pattern Matching Stage 3 ES2027 (expected) Babel plugin, V8 in progress
Pipeline Operator (|>) Stage 3 ES2027 (expected) Babel plugin, TC39 consensus
Import Defer Stage 3 ES2027 (expected) Babel plugin, bundler support
Temporal API Stage 4 ES2027 Polyfill, Node 24+ experimental

Adoption Strategy: How to Start Today

ES2026 features are usable today, but the approach differs by feature:

For New Projects

Use Node.js 24+ for using/await using and Math.sumPrecise() without any transpilation. For browser applications, add the ES2026 Babel preset:

# Install the Babel plugin
npm install --save-dev @babel/preset-env @babel/plugin-proposal-explicit-resource-management

# In babel.config.js
module.exports = {
  presets: [
    ['@babel/preset-env', {
      targets: { esmodules: true },
    }],
  ],
  plugins: [
    '@babel/plugin-proposal-explicit-resource-management',
  ],
};

For Existing Projects

Start with Error.isError() and Math.sumPrecise() — they're drop-in additions that won't break anything. Then incrementally adopt using in resource-heavy modules (file I/O, database connections, file streams). Save Pattern Matching and the Pipeline Operator for greenfield code where you can set up the Babel plugin from the start.

For Temporal

Add the polyfill to your package.json today and start replacing Date usage incrementally. Temporal is designed so that when native support ships, you simply remove the polyfill import — the API surface is identical.

FAQ

What is ES2026 and when was it released?
ES2026 (ECMAScript 2026) is the 2026 edition of the ECMAScript specification that standardizes JavaScript. It was finalized by TC39 in mid-2026. This edition includes explicit resource management (using/await using), Math.sumPrecise, Error.isError, and several other utility features. Stage 3 proposals like Pattern Matching and the Pipeline Operator are progressing alongside and expected in ES2027.
What does using and await using do in JavaScript?
using and await using automatically clean up resources when they go out of scope — no more try/finally blocks. using is for synchronous resources (file handles), and await using is for async resources (database connections). Both use Symbol.dispose and Symbol.asyncDispose respectively. This eliminates resource leaks and makes code more readable. Node.js 24+ and Chrome 126+ support this natively.
Is the Temporal API included in ES2026?
Temporal reached Stage 4 in March 2026 but is slated for ES2027, not ES2026. However, you can use the official polyfill today in any Node.js or browser environment. Temporal provides immutable, timezone-aware date/time objects as a complete replacement for Date. Types include PlainDate, ZonedDateTime, Instant, and Duration.
What is Pattern Matching in JavaScript?
Pattern Matching (Stage 3) introduces match expressions that let you destructure values against patterns declaratively — similar to Rust or Haskell. You can match against object shapes, array positions, literal values, and more. It replaces lengthy if-else chains and switch statements with concise, readable pattern clauses. A Babel plugin is available for experimentation.
What does the Pipeline Operator do?
The Pipeline Operator (|>, Stage 3) enables left-to-right function composition. Instead of writing fn3(fn2(fn1(value))), you write value |> fn1 |> fn2 |> fn3. The topic token (%) lets you reference the piped value in multi-argument functions. It makes data transformation pipelines far more readable compared to deeply nested calls.
What is Math.sumPrecise in ES2026?
Math.sumPrecise is a new static method (Stage 4, shipping in ES2026) that computes the sum of an iterable of numbers using a compensated summation algorithm. It significantly reduces floating-point rounding errors compared to manual addition. It's ideal for financial calculations, statistics, and scientific computing where precision matters.
How can I start using ES2026 features today?
Use Node.js 24+ for native support of using, Math.sumPrecise, and Error.isError. For browsers, use Babel with the es2026 preset or individual plugins. For Temporal, add the polyfill. For Pattern Matching and Pipeline Operator, use Babel plugins. Most features are safe to adopt incrementally — they're additions that won't break existing code. To stay ahead of how browsers implement these features, follow platform announcements like Google I/O 2026 which shapes Chrome's implementation roadmap. For a hands-on look at new browser APIs built on modern JavaScript, see my WebMCP guide — WebMCP uses the navigator.modelContext API, an example of how ES2026-era JavaScript patterns power next-generation web platform features.

Need Help with Modern JavaScript?

ES2026 brings significant changes to JavaScript, and keeping up with the evolving language can be challenging. Whether you're modernizing an existing codebase, starting a new project, or need guidance on the best tooling setup, I can help.

I'm a senior full-stack developer with 20+ years of experience in JavaScript, React, Node.js, and modern web development. Based in Minsk and working worldwide, let's discuss your project.

For a broader perspective on the JavaScript ecosystem, also check my guide on React vs Vue.js vs Angular, my analysis of the 2026 npm supply chain attack, and my Chrome Prompt API guide for browser-native AI integration.

Contact

Let's discuss your project

Tell me about your project — I'll recommend the best technology stack and provide a preliminary estimate. Free of charge.