let vs const
let vs const in JavaScript: which to reach for by default, and what const actually protects against.
Last updated
The short answer
Default to const; reach for let only when you know the binding will be reassigned — a loop counter, an accumulator, a value that genuinely changes. This isn't just style — const catches an accidental reassignment at parse time, and a codebase that's mostly const makes the few lets stand out as the places state actually changes.
| Dimension | let | const |
|---|---|---|
| Reassignment | Allowed | Throws a TypeError |
| Mutability | Value can be reassigned | Binding is fixed, contents can still mutate |
| Scope | Block-scoped | Block-scoped |
| Hoisting | Hoisted, temporal dead zone applies | Hoisted, temporal dead zone applies |
| Common use | Loop counters, accumulators, reassigned state | Everything else — the default choice |
Choose let when
- →A classic for-loop counter that needs to be reassigned on each iteration.
- →An accumulator or running value built up across a loop or callback — a running total, a found-item flag.
- →A variable that's genuinely conditionally assigned later — declared once, set in one of several branches.
Choose const when
- →The default for everything — function results, imported values, object and array bindings you won't reassign.
- →You want the parser to catch an accidental reassignment as a bug, not a silent overwrite three functions later.
- →You're declaring an object or array whose contents may change (push, mutate a property) but whose reference never will.
The catch nobody mentions
const doesn't make anything immutable — it only prevents the variable from being reassigned to a different value. `const arr = []; arr.push(1);` is perfectly legal, and so is `const obj = {}; obj.name = 'x';`. For actual immutability you need Object.freeze() (shallow) or a library that enforces it deeply — const alone won't stop a nested property from changing.