Skip to content

temporal dead zone (TDZ)

The temporal dead zone (TDZ) is the time between entering a scope and running a let, const, or class declaration in it, during which any read or write of the declared name throws a ReferenceError.

Hoisting creates a binding for each of these declarations, the link between its name and its value, as soon as its scope starts, but leaves it uninitialized until the declaration runs. The ECMAScript specification (ECMA-262) doesn’t use the name TDZ. It says that a let or const variable may not be accessed in any way until its declaration is evaluated.

The word temporal refers to execution order. The zone ends when the declaration runs, so a function written above the declaration can read the binding if the call happens later. Even typeof, which returns "undefined" for a name that was never declared, throws on a binding in its TDZ.

Example

Say a module defines a helper near the top of the file that reads a configuration constant declared further down:

Language: JavaScript Filename: upload-limit.mjs
function describeLimit() {
  return `Upload limit: ${uploadLimit} files`;
}

try {
  console.log(describeLimit());
} catch (error) {
  console.log(`${error.name}: ${error.message}`);
}

const uploadLimit = 5;
console.log(describeLimit());

Running the file calls the same helper twice, once before and once after the declaration:

Language: Shell
$ node upload-limit.mjs
ReferenceError: Cannot access 'uploadLimit' before initialization
Upload limit: 5 files

The first call runs while uploadLimit is still in its TDZ, so reading it throws. The second call runs after the declaration has initialized the binding, so the same line of code works.

The TDZ also catches a common shadowing mistake, where a block reuses an outer name while cleaning up its value:

Language: JavaScript
> const discountCode = " SPRING10 ";
undefined

> if (discountCode) {
…   const discountCode = discountCode.trim();
… }
Uncaught ReferenceError: Cannot access 'discountCode' before initialization

The inner const owns the name discountCode for the whole block, so the right-hand side reads the inner binding while it’s still in its TDZ. The outer discountCode is out of reach inside the block.

Have a question about this? Mentor AI can show you examples, compare related terms, and point you to tutorials.


By Leodanis Pozo Ramos • Updated Nov. 5, 2026