Node.js 26 makes Temporal the default: replace Date in 2026 (with code)

Node.js 26 ships Temporal by default. Migrate off Date with Instant, ZonedDateTime and PlainDate, bridging old code via toTemporalInstant().

Read time
11 min
Word count
1.5K
Sections
11
FAQs
8
Share
Hero: Node.js 26 enables the Temporal API by default in 2026, replacing the Date object
Node.js 26 ships the Temporal API by default in 2026: immutable, timezone-first dates that replace the Date object.
On this page · 11 sections
  1. What Temporal fixes
  2. The Temporal types you will actually use
  3. A Date-to-Temporal migration map
  4. Gotchas that will bite
  5. Before you upgrade to Node.js 26
  6. Older runtimes and cross-environment code
  7. India-specific considerations
  8. Bottom line
  9. FAQ
  10. How eCorpIT can help
  11. References

Summary. Node.js 26.0.0 shipped on May 5, 2026 with the Temporal API enabled by default, no flag required, alongside V8 14.6 and Undici 8.0. Temporal is the modern replacement for the Date object, and it reached TC39 Stage 4 on March 13, 2026, which locks it into the ECMAScript 2026 standard. It brings immutable date and time types, first-class IANA time zones and calendars, and nanosecond precision, and it ships with around 4,500 conformance tests against Date's 594. You do not rewrite everything at once: the migration is incremental, bridged by Date.prototype.toTemporalInstant(), and older runtimes can load a polyfill. Node 26 also carries breaking changes unrelated to dates, so check those before you bump the version. This guide gives the types you will actually use, a Date-to-Temporal migration map with code, the gotchas that bite, and the upgrade checks to run first.

Date has been JavaScript's weak spot since the language shipped. Philip Chimento and Ujjwal Sharma of Igalia co-championed the fix, and the firm's Stage 4 announcement is blunt: Temporal "replaces JavaScript's Date API, which has badly underserved developers since 1995." Getting date logic right is worth the effort, because the failure mode is silent: an off-by-one-day or a mishandled offset corrupts data long before anyone notices. Teams that add real timezone and calendar coverage grow their CI matrices, and at GitHub Actions' $0.006 per Linux minute in 2026 those runs are not free, so it pays to migrate once and correctly. Node 26 removes the last excuse, because Temporal is now in the runtime with no dependency to install.

What Temporal fixes

The Date object has four structural problems Temporal removes. Date is mutable, so setMonth changes the object in place and aliasing bugs follow. Date has no concept of a time zone beyond the host's local offset and UTC, so anything involving another zone means manual math or a library. Date conflates a wall-clock date, a wall-clock time and an exact instant into one type, so "a birthday" and "a precise timestamp" share the same broken API. And Date parsing is famously loose.

Temporal splits those concerns into explicit, immutable types. An exact moment is a Temporal.Instant with nanosecond precision. A moment in a specific zone is a Temporal.ZonedDateTime, which carries an IANA zone and a calendar. A calendar date with no zone is a Temporal.PlainDate. Arithmetic returns a new value rather than mutating the old one. The maturity shows in the test suite: Temporal ships with roughly 4,500 test262 conformance tests, where Date has 594. Firefox 139, Chrome 144, Edge 144 and the TypeScript 6.0 beta already include it, and now so does Node.js 26.

The Temporal types you will actually use

Most migrations touch five or six types. Pick the type by the question "does this value have a time zone, and does it have a time-of-day?" rather than reaching for one catch-all.

Type Represents Use instead of
Temporal.Instant An exact moment, nanosecond precision Date for timestamps and logging
Temporal.ZonedDateTime An instant in a named IANA zone plus calendar Date with manual offset math
Temporal.PlainDate A calendar date, no time or zone Date for birthdays, due dates, invoices
Temporal.PlainTime A wall-clock time, no date ad-hoc "HH:mm" string handling
Temporal.PlainDateTime A date and time with no zone Date used as a "local" datetime
Temporal.Duration A length of time manual millisecond arithmetic

The rule of thumb: store and compare exact moments as Instant, do human-facing calculations in ZonedDateTime, and use PlainDate for anything that is a date on a calendar rather than a point on the world clock.

A Date-to-Temporal migration map

You can migrate file by file. The table below is the core mapping; the code that follows shows each pattern in context.

Task Legacy Date Temporal
Current timestamp Date.now() Temporal.Now.instant()
Current wall clock in a zone new Date() plus a library Temporal.Now.zonedDateTimeISO('Asia/Kolkata')
Parse a calendar date new Date('2026-01-15') Temporal.PlainDate.from('2026-01-15')
Add six months manual month math date.add({ months: 6 })
Difference between dates millisecond subtraction a.until(b, { largestUnit: 'day' })
Bridge an existing Date not applicable existing.toTemporalInstant()

Timestamps and the bridge from Date

For a precise moment, replace Date.now() with Temporal.Now.instant(). When you receive a Date from an older library or a database driver, convert it with the toTemporalInstant method added to Date.prototype:


            // Old
const ts = Date.now();                 // number of milliseconds

// New
const now = Temporal.Now.instant();    // nanosecond-precision Instant
console.log(now.epochMilliseconds);    // interop with millisecond APIs

// Bridge a Date you were handed
const legacy = new Date('2026-01-15T09:30:00Z');
const asInstant = legacy.toTemporalInstant();
const inKolkata = asInstant.toZonedDateTimeISO('Asia/Kolkata');
console.log(inKolkata.toString());     // 2026-01-15T15:00:00+05:30[Asia/Kolkata]
          

Calendar dates and arithmetic

Use PlainDate for values that are dates, not instants, such as an invoice date or a date of birth. Arithmetic is immutable and reads like the intent:


            const due = Temporal.PlainDate.from('2026-01-15');
const nextCycle = due.add({ months: 6, days: 15 });   // 2026-07-30, new value
const daysLeft = Temporal.Now.plainDateISO().until(due, { largestUnit: 'day' });
console.log(daysLeft.days);

// Comparisons are explicit, no < or > coercion
if (Temporal.PlainDate.compare(nextCycle, due) > 0) {
  // nextCycle is later
}
          

Wall-clock work in a real zone

ZonedDateTime does the offset and daylight-saving math for you. Ask for "9am next Monday in New York" without touching an offset table:


            const meeting = Temporal.ZonedDateTime.from({
  year: 2026, month: 3, day: 9, hour: 9, minute: 0,
  timeZone: 'America/New_York',
});
const inIndia = meeting.withTimeZone('Asia/Kolkata');
console.log(inIndia.toString());   // same instant, +05:30 wall clock
          

Serialization and formatting

Temporal serializes to strings that keep the zone and calendar, using the RFC 9557 IXDTF format (for example a trailing [Asia/Kolkata] annotation). Store the string, parse it back losslessly, and format for humans with Intl:


            const zdt = Temporal.Now.zonedDateTimeISO('Asia/Kolkata');
const stored = zdt.toString();            // round-trippable, keeps the zone
const back = Temporal.ZonedDateTime.from(stored);

const label = back.toLocaleString('en-IN', {
  dateStyle: 'medium', timeStyle: 'short',
});
          

Persist an exact moment as either the IXDTF string or instant.epochNanoseconds, and reconstruct with Temporal.Instant.from(...). Do not store a formatted local string as your source of truth.

Gotchas that will bite

The most common mistake is reaching for PlainDateTime when you mean ZonedDateTime. A PlainDateTime has no zone, so "March 9 at 2am" is not a real instant until you attach a zone, and in a spring-forward transition that wall-clock time may not exist at all. If a value must map to a point on the world clock, use ZonedDateTime or Instant.

Two more that catch teams. First, do not quietly convert Temporal values back to Date at the edges and lose precision or zone information; keep them as Temporal all the way to the boundary and convert only when an external API demands a Date. Second, when you serialize across calendar systems, keep the calendar annotation ([u-ca=hebrew] and similar) that RFC 9557 defines, or round-tripping a non-ISO calendar date will drop information. Our interop 2026 web platform guide covers the broader pattern of adopting new platform primitives without breaking the boundaries of your system.

Before you upgrade to Node.js 26

Temporal is the headline, but Node 26 is a major release with removals that can crash an app on the first restart. Audit these before you bump the version, not after.

Change Impact Fix
http.writeHeader() removed Middleware calling it crashes on startup Switch to writeHead()
Legacy _stream_readable / _stream_transform removed Import-time failures Use require('stream').Readable, Writable and pipeline
Readable streams read one buffer at a time Throughput and backpressure behaviour shifts Re-test stream consumers under load
customization-hooks loader runtime-deprecated DeprecationWarning, removal later Plan the loader migration now
localStorage returns undefined with no persistence file Tests relying on in-memory state break Configure persistence or mock it
Build: GCC 13.2, no Python 3.9 Native addons fail to compile Rebuild native addons for the new module version

The riskier the jump, the more this matters: an app that skipped upgrades since Node 22 will likely hit several of these at once. Run npm outdated and look for packages untouched since Node 16, which are the ones most likely to reach into removed internals. This is the same "evaluate on Current, promote at LTS" discipline we describe in our note on Node.js moving to one release per year; Node 26 becomes LTS in October 2026.

Older runtimes and cross-environment code

If part of your stack runs on a runtime without Temporal yet, load a polyfill and keep one API across environments. The lightweight temporal-polyfill from FullCalendar is about 20 KB, and the reference @js-temporal/polyfill maintained by the champions is about 44 KB. Because Temporal is Stage 4 and already in Firefox 139, Chrome 144, Edge 144 and Node 26, the polyfill is a shrinking, temporary cost rather than a permanent dependency. Teams already running native TypeScript workflows through Node's native type stripping or weighing the TypeScript 7 migration can fold the Temporal move into the same toolchain pass.

India-specific considerations

For teams building out of India, the Asia/Kolkata zone is a live test of your date code, because its offset is a half hour, +05:30, and a surprising amount of naive code assumes whole-hour offsets. Temporal handles it correctly through the IANA database with no special casing. The bigger win is multi-zone scheduling: product teams serving both India and the US spend real engineering time reconciling +05:30 against US zones that observe daylight saving, and ZonedDateTime.withTimeZone does that conversion without an offset table. For services where date correctness underpins money, such as billing, payroll and settlement windows, moving that logic onto explicit Temporal types removes a class of silent errors before it reaches production.

Bottom line

Node.js 26 makes Temporal a runtime default, so the migration is now a code change rather than a dependency decision. Move exact moments to Instant, human-facing math to ZonedDateTime, and calendar values to PlainDate, bridging existing Date objects with toTemporalInstant() so you can go file by file. Audit the Node 26 breaking changes before you upgrade, keep a polyfill only where a runtime still lacks Temporal, and store dates as IXDTF strings or epoch nanoseconds rather than formatted local text. The payoff is a whole category of timezone and mutation bugs that simply stops happening.

FAQ

How eCorpIT can help

eCorpIT is a CMMI Level 5 and ISO 27001:2022 certified engineering organisation in Gurugram, and our senior-led teams run Node.js upgrades and date-handling migrations on production systems. We can audit a codebase for the Node 26 breaking changes, plan an incremental Date-to-Temporal move with tests around your timezone and calendar logic, and keep a polyfill only where a runtime still needs it. If you want a Node 26 and Temporal migration plan, talk to our engineering team.

References

  1. Node.js 26.0.0 release (nodejs/node PR #62526, GitHub)
  1. Node.js 26 ships with Temporal API enabled by default (Help Net Security)
  1. Node.js 26: Temporal API Enabled by Default, V8 14.6 (InfoQ)
  1. Temporal Reaches Stage 4 (Igalia)
  1. Temporal (MDN Web Docs)
  1. Temporal proposal (TC39)
  1. temporal-polyfill (FullCalendar, GitHub)
  1. Reference Temporal polyfill (js-temporal, GitHub)
  1. Node.js 26 upgrade checklist (IT Academy)
  1. Simpler pricing for GitHub Actions, 2026 (GitHub Changelog)
  1. Temporal: The 9-Year Journey to Fix Time in JavaScript (Bloomberg JS blog)

_Last updated: July 28, 2026._

Frequently asked

Quick answers.

01 Is the Temporal API stable enough to use in production?
Yes. Temporal reached TC39 Stage 4 on March 13, 2026, which finalises it into the ECMAScript 2026 standard, and Node.js 26 enables it by default. It ships with roughly 4,500 conformance tests and is already in Firefox 139, Chrome 144 and Edge 144. For runtimes that lack it, a polyfill provides the same API during the transition.
02 Do I have to rewrite all my Date code at once?
No. The migration is incremental. Date.prototype.toTemporalInstant() bridges any existing Date into a Temporal.Instant, so you can convert at the edges and migrate module by module. Keep the value as a Temporal type through your logic and convert back to Date only when an external API requires it. There is no need for a big-bang rewrite.
03 When did Node.js enable Temporal by default?
Node.js 26.0.0, released on May 5, 2026, is the first version with the Temporal API on by default, with no --harmony flag needed. The same release ships V8 14.6 and Undici 8.0. Node 26 stays the Current release for about six months and enters long-term support in October 2026.
04 Which Temporal type replaces the Date object?
It depends on what the value means. Use Temporal.Instant for exact timestamps, Temporal.ZonedDateTime for a moment in a specific IANA time zone, and Temporal.PlainDate for a calendar date with no time or zone. The point of Temporal is that one Date type is split into several explicit ones, so you pick by zone and time-of-day.
05 How do I store Temporal values in a database?
Store an exact moment as its IXDTF string, defined by RFC 9557, or as instant.epochNanoseconds, and reconstruct with Temporal.Instant.from(...). For zoned values, the string form keeps the time zone and calendar annotation so it round-trips losslessly. Avoid storing a formatted, human-readable local string as your source of truth.
06 What breaks when I upgrade to Node.js 26?
Beyond dates, Node 26 removes http.writeHeader() and the legacy _stream_readable and _stream_transform modules, changes Readable streams to read one buffer at a time, runtime-deprecates the customization-hooks loader, and changes localStorage to return undefined without a persistence file. Building from source now needs GCC 13.2 and drops Python 3.9. Audit these before upgrading.
07 Do I still need Moment.js, Luxon or date-fns?
For most new code, no. Temporal covers immutable types, time-zone and calendar math, durations and parsing that those libraries were built to provide. Existing code can keep a library during the transition, but Temporal is now native in Node 26 and modern browsers, so new work should target it and drop the third-party dependency over time.
08 Does Temporal handle the Asia/Kolkata half-hour offset correctly?
Yes. Temporal uses the IANA time-zone database, so the +05:30 offset for Asia/Kolkata is handled without special casing, unlike naive code that assumes whole-hour offsets. Converting between India and daylight-saving zones is a single withTimeZone call on a ZonedDateTime, with no manual offset tables and no seasonal edge cases to maintain.

About the author

Manu Shukla

Founder & Director

Founder of eCorpIT. Hands-on engineer leading senior-only delivery for AI apps, custom software, and cloud systems for global clients.

Subscribe

One engineering note a week. No fluff, no spam.

Senior-architect playbooks on AI agents, mobile apps, cloud, security, data, and marketing — delivered every Wednesday.

Past the reading

Read enough. Let's build something.

A senior architect responds in 24 working hours with scope, indicative cost, and a timeline. NDA before any technical conversation.