If you've been learning JavaScript recently, you've probably seen all three of these in different tutorials:
var name = "Alice";
let name = "Alice";
const name = "Alice";
They all look like they do the same thing. They don't — and picking the wrong one can introduce bugs that are genuinely hard to track down.
Here's the short version, followed by the reasoning so you actually remember it:
Use const by default. Use let when you need to reassign. Never use var.
That's it. That's the rule. If you stop reading here and just follow it, your code will be better than about 60% of the JavaScript I see in the wild.
But let's look at why, because understanding the reasoning is how you stop second-guessing yourself at 2 a.m. debugging a scope bug.
What's Different About These Three?
Two things: scope and reassignability.
Scope
var is function-scoped. let and const are block-scoped.
This sounds like jargon until you see it bite:
function example() {
if (true) {
var x = 1;
let y = 2;
}
console.log(x); // 1 — var leaks out of the if block
console.log(y); // ReferenceError — let stays inside
}
var doesn't care about { } blocks. It only cares about functions. So variables declared with var inside an if, for, or while block leak out into the surrounding function. This is almost never what you want.
let and const respect { } blocks. They only exist inside the block they were declared in. This matches how every other modern language works, and how your brain probably already expects variables to work.
Reassignability
var and let can be reassigned. const cannot.
let count = 0;
count = 1; // fine
const PI = 3.14;
PI = 3.14159; // TypeError: Assignment to constant variable
This is the main reason people reach for let — "I need to change the value later." Fair. But most of the time, you actually don't.
Why const Should Be Your Default
Here's a habit that will quietly improve your code: assume const until proven otherwise.
Start with const. If you hit a moment where you genuinely need to reassign, change it to let. Most of the time, you won't need to.
Why this works:
1. const makes your code easier to read.
When I read const user = getUser(), I know that user refers to the same thing for the rest of this block. I don't have to scan the next 40 lines checking whether someone reassigned it. That's mental overhead I don't have to carry.
2. It catches bugs at write-time, not run-time.
If you try to reassign a const, your editor yells at you immediately. If you accidentally reassign a let somewhere, you don't find out until the program misbehaves.
3. It forces better function design.
A function that reassigns variables often wants to be broken into smaller functions that return values. Defaulting to const nudges you in that direction without you having to think about it.
"But const Doesn't Really Mean Constant, Right?"
Right — and this is the one gotcha worth mentioning.
const means the variable binding can't be reassigned. It does not mean the value is frozen.
const user = { name: "Alice" };
user.name = "Bob"; // works fine — we're mutating, not reassigning
user = { name: "Bob" }; // TypeError — this is reassignment
For objects and arrays, const only prevents you from pointing the variable at a different object. You can still modify the object's internals.
If you need true immutability, use Object.freeze() — but in 99% of day-to-day code, const does exactly what you want.
When to Actually Use let
There are legitimate cases. The most common ones:
1. Counters in loops (when not using for...of):
for (let i = 0; i < items.length; i++) {
// i gets reassigned each iteration
}
2. Values that change based on conditions:
let message;
if (user.isAdmin) {
message = "Welcome, admin";
} else {
message = "Welcome";
}
Though honestly, even this example is cleaner as a ternary or a function:
const message = user.isAdmin ? "Welcome, admin" : "Welcome";
3. Accumulators in loops (though reduce is often better):
let total = 0;
for (const item of cart) {
total += item.price;
}
That's about it. If you find yourself reaching for let frequently, it's worth pausing to ask whether a const with a cleaner expression would work.
Why Never var?
A few reasons, any of which is disqualifying on its own:
1. It leaks out of blocks (as we saw above)
2. It gets hoisted as undefined:
console.log(x); // undefined, not an error
var x = 5;
Compare to:
console.log(y); // ReferenceError — much better
let y = 5;
The let version fails loudly. The var version fails silently, and undefined propagates through your program until it causes a weird bug somewhere else.
3. You can redeclare it without errors:
var name = "Alice";
var name = "Bob"; // no error — fine
This means typos and copy-paste mistakes go undetected. let and const throw an error if you try to redeclare.
The only reason to ever write var today is if you're maintaining old code that already uses it. Even then, many teams run refactors to replace it.
A Quick Decision Flowchart
Next time you're about to declare a variable, ask yourself:
-
Will this value be reassigned? → If no, use
const. (This will be true most of the time.) -
Does it need to exist in this scope only? → Yes, use
let. -
Am I thinking about
var? → Don't.
The One-Line Summary
Default to
const. Reach forletwhen you need to reassign. Treatvaras deprecated.
If you apply that single rule consistently for a week, you'll stop thinking about this question entirely — and your code will get cleaner as a side effect.
If you have a case where let or var is genuinely the right call and my rule of thumb breaks down, I'd love to hear about it in the comments. Those edge cases are usually where the most interesting JavaScript lives.
Top comments (0)