JavaScript Temporal Dead Zone (TDZ)
If you try to access a let or const variable before its declaration, JavaScript throws an error.
The period between the start of the scope and the declaration being reached is called the Temporal Dead Zone (TDZ).
What Is the TDZ
When a let or const variable enters a scope, it's hoisted — but not initialized.
From the moment the scope begins to the point where the declaration is executed, the variable is in the TDZ. Accessing it during this window throws a ReferenceError:
console.log(name); // ReferenceError: Cannot access 'name' before initialization
let name = "Charmy";Once the declaration runs, the TDZ ends and the variable is available:
let name = "Charmy";
console.log(name); // "Charmy"The Boundaries of the TDZ
The TDZ starts at the beginning of the scope and ends when the declaration is reached.
{
// TDZ starts here
console.log(name); // ReferenceError
let name = "Charmy"; // TDZ ends here
console.log(name); // "Charmy"
}The TDZ is scoped, not file-wide. Each scope has its own TDZ for each variable declared within it.
This means a variable in an inner scope can shadow an outer one — and still have its own TDZ:
let name = "global";
{
console.log(name); // ReferenceError — not "global"
let name = "local";
}The inner let name creates its own TDZ in the block, shadowing the outer name. Accessing it before the declaration throws an error rather than falling back to the outer value.
TDZ vs. var
var has no TDZ. Accessing it before the declaration returns undefined instead of throwing:
console.log(a); // undefined
var a = 1;
console.log(b); // ReferenceError
let b = 2;The difference comes down to initialization timing:
var— hoisted and immediately initialized toundefinedlet/const— hoisted but not initialized; enters the TDZ until the declaration runs
TDZ in Default Parameters
The TDZ also applies inside functions that use default parameter values.
Default values are evaluated left to right when the function is called. If a later parameter references an earlier one that hasn't been initialized yet, you'll hit the TDZ:
// Fine — b's default references a, which is already initialized
function greet(a = 1, b = a) {
console.log(a, b); // 1 1
}
greet();// Error — a's default references b, which hasn't been initialized yet
function greet(a = b, b = 1) {
console.log(a, b);
}
greet(); // ReferenceError: Cannot access 'b' before initializationWhy the TDZ Exists
The TDZ is intentional. It makes code safer and bugs easier to catch.
With var, accessing a variable before its declaration doesn't throw — it just returns undefined. That can mask bugs and make them harder to track down:
console.log(count); // undefined — no error, easy to miss
var count = 10;With let and const, the error is immediate:
console.log(count); // ReferenceError — you know exactly what went wrong
let count = 10;The TDZ turns "declare before you use" from a best practice into a hard rule.
Conclusion
- The TDZ is the period during which a
letorconstvariable exists but can't be accessed - It starts at the beginning of the scope and ends when the declaration is reached
- Accessing a variable in the TDZ throws a
ReferenceError varhas no TDZ — accessing it early returnsundefinedinstead- The TDZ is by design: it forces you to declare variables before using them, making bugs easier to catch
Once you're comfortable with the TDZ, the natural next topics are:
- Hoisting
- Scope
- Execution Context