Menu
Try in Playground

JavaScript Nullish Coalescing (??): Defaults Done Right

How the ?? operator picks a default only when a value is null or undefined — and why that beats || for most real-world defaults.

A Smarter Default

JavaScript has always had a shortcut for defaults: value || fallback. It mostly works, but it has a bug built into it — it treats any falsy value as missing. 0, '', and false all trigger the fallback, even when they're the real answer.

The nullish coalescing operator ?? fixes that. It only falls back on null or undefined:

index.js
Output
Click Run to see the output here.

0 and '' survive. null and undefined don't. That's the whole operator.

Why || Isn't Enough

Here's the classic bug ?? was designed to prevent:

index.js
Output
Click Run to see the output here.

The user asked for volume 0 (silence) and an empty nickname. Both got silently overwritten because || can't tell "missing" apart from "falsy."

Swap in ??:

index.js
Output
Click Run to see the output here.

Now 0 and '' pass through untouched, and only genuinely missing fields get the default. This is almost always what you want.

The Mental Model

?? asks one question: is the left side null or undefined? Nothing else counts.

Left valueleft || right returnsleft ?? right returns
nullrightright
undefinedrightright
0rightleft (0)
''rightleft ('')
falserightleft (false)
NaNrightleft (NaN)
any objectleftleft

Pick ?? when your data has meaningful falsy values. Pick || when you genuinely want to reject everything falsy (short strings, zero counts, etc.) — that case exists, but it's rarer than people assume.

Short-Circuiting

Like || and &&, ?? short-circuits. If the left side isn't nullish, the right side doesn't run at all:

index.js
Output
Click Run to see the output here.

expensiveDefault() only runs once — for b. That's useful when your fallback is a function call, a network request, or anything else you'd rather skip when it isn't needed.

Pairing With Optional Chaining

?? and ?. were introduced together in ES2020, and they're designed to work as a team. Optional chaining walks through a possibly-missing path and yields undefined if any step is missing; nullish coalescing then fills in a sensible default:

index.js
Output
Click Run to see the output here.

Without this pair, the same code is an ugly chain of && checks or a try/catch. With them, safe access and sane defaults fit on one line.

Nullish Assignment: ??=

a ??= b assigns b to a only when a is null or undefined. It's the logical nullish assignment operator, and it short-circuits — if a already has a value, the right-hand side isn't evaluated.

index.js
Output
Click Run to see the output here.

Notice that verbose: false and retries: 0 are preserved — ??= only fills in what's truly missing. Compare with ||=, which would clobber both.

Precedence and the Parentheses Rule

?? deliberately refuses to mix with || or && without parentheses. This throws a SyntaxError:

const x = a || b ?? c;   // SyntaxError

The language designers decided the precedence was ambiguous enough to be worth forcing you to clarify. Add parentheses and it's fine:

index.js
Output
Click Run to see the output here.

Different groupings, different answers. The parentheses aren't decorative — they're telling future readers (and the parser) what you meant.

Not the Same as a Default Parameter

Default parameters in function signatures have their own rule: they only kick in when the argument is undefined, not null. That's a subtle difference from ??, which treats both the same.

index.js
Output
Click Run to see the output here.

If you want null to trigger the fallback too, use ?? inside the body:

index.js
Output
Click Run to see the output here.

Small distinction, easy to trip over when an API hands you null for "no value set."

When to Reach for ??

Use ?? as your default operator unless you have a specific reason not to. It's the one that matches how most data actually behaves — 0, '', and false are usually real values worth keeping, and only truly missing data deserves a fallback. Reserve || for the cases where you genuinely want any falsy value replaced.

Next: Classes

That's it for objects and arrays — you've got the tools to build and navigate data shapes safely. The next chapter moves to organizing behavior: classes, inheritance, and the prototype system underneath them.

Frequently Asked Questions

What is the nullish coalescing operator in JavaScript?

?? returns its right-hand side only when the left-hand side is null or undefined. Otherwise it returns the left-hand side unchanged. value ?? fallback is the standard way to supply a default without tripping on falsy-but-valid values like 0 or ''.

What's the difference between ?? and || in JavaScript?

|| falls back on any falsy value — 0, '', false, NaN, null, undefined. ?? only falls back on null and undefined. If 0 or an empty string is a legitimate value in your data, use ??. If you truly want to reject all falsy values, || is still correct.

Can you combine nullish coalescing with optional chaining?

Yes, and it's a common pairing. user?.settings?.theme ?? 'light' walks the chain safely, yields undefined if anything along the way is missing, then swaps in 'light'. The two operators were shipped together in ES2020 specifically to support this pattern.

What does the ??= operator do?

a ??= b assigns b to a only if a is currently null or undefined. It's logical nullish assignment — shorthand for a = a ?? b, but it short-circuits: if a already has a value, the right-hand side isn't even evaluated. Handy for filling in missing defaults on an options object.

Learn to code with Coddy

GET STARTED