JavaScript Nullish Coalescing Operator (??)
Learn the JavaScript nullish coalescing operator (??), how it differs from ||, and operator precedence rules.
The nullish coalescing operator (??) is a short, expressive way to supply a default value in JavaScript. It returns its right-hand operand only when the left-hand operand is nullish — that is, null or undefined — and otherwise hands back the left-hand value untouched. Introduced in ES2020, it solves a long-standing problem with using the || operator for defaults, and it works hand in hand with optional chaining and the logical operators you already know.
What "Nullish" Means
A value is considered nullish when it is exactly null or undefined. Every other value — including falsy ones like 0, '', false, and NaN — is treated as a real, intentional value by ??.
null ?? 'default' // 'default'
undefined ?? 'default' // 'default'
0 ?? 'default' // 0
'' ?? 'default' // ''
false ?? 'default' // false
NaN ?? 'default' // NaNThe rule is simple: if the left side is null or undefined, you get the right side; otherwise you get the left side.
How ?? Differs From ||
This is the most important reason ?? exists. The logical OR operator (||) returns the right-hand side whenever the left-hand side is any falsy value — 0, '', false, NaN, null, and undefined all count. That behavior is fine until 0 or an empty string is a legitimate value, at which point || quietly produces the wrong result.
Consider a counter whose valid value can be 0:
let count = 0;
let withOr = count || 100; // 100 — wrong! 0 got replaced
let withNullish = count ?? 100; // 0 — correct, 0 was preservedBecause 0 is falsy, || treats it the same as "no value" and falls through to 100. The ?? operator recognizes that 0 is not nullish and keeps it. The same trap applies to empty strings:
Reach for ?? instead of || whenever 0, '', or false are valid inputs. Using || for defaults in those cases is one of the most common sources of subtle bugs in JavaScript — for example, a quantity of 0 becoming 1, or a blank search field defaulting to some placeholder text.
Precedence and Parentheses
The ?? operator has low precedence — about the same level as || and lower than arithmetic and comparison operators. In practice this means the fallback is resolved before the value is used in a larger expression, but you should still group with parentheses to keep intent clear.
let height = null;
let width;
// Each ?? is evaluated, then the products are multiplied
let area = (height ?? 100) * (width ?? 50);
console.log(area); // 100 * 50 = 5000Without the parentheses the multiplication would bind more tightly than you might expect, so wrapping each default in ( ... ) keeps the math unambiguous and readable.
Combining ?? With && or || Is Forbidden
JavaScript deliberately refuses to let you mix ?? with && or || in the same expression without parentheses. Doing so is a SyntaxError, because the precedence between them would be ambiguous and easy to misread.
// SyntaxError: Unexpected token '||'
let result = a ?? b || c;
// Fix it by grouping explicitly:
let safe = (a ?? b) || c; // valid
let other = a ?? (b || c); // also valid, different meaningThe two valid forms mean different things, which is exactly why the language makes you choose. Add the parentheses and state precisely what you intend.
The restriction only applies when ?? sits directly alongside && or ||. You are free to use them in separate expressions, and parentheses always resolve the ambiguity.
Logical Assignment Operators
ES2021 added three logical assignment operators that pair an assignment with a logical check. They assign to the left-hand variable only when a condition is met, which makes them perfect for filling in defaults and conditional updates.
Nullish Assignment (??=)
x ??= y assigns y to x only if x is currently null or undefined. It is the assignment form of ?? and the most common of the three for setting defaults on an object.
let settings = { theme: 'dark' };
settings.theme ??= 'light'; // already set → stays 'dark'
settings.fontSize ??= 16; // missing → becomes 16
console.log(settings); // { theme: 'dark', fontSize: 16 }Logical OR Assignment (||=)
x ||= y assigns y to x when x is falsy (0, '', false, null, undefined, NaN). Like ||, it can overwrite valid falsy values, so use it only when any falsy value truly means "replace me."
Logical AND Assignment (&&=)
x &&= y assigns y to x only when x is truthy. It is handy for updating a value that already exists without creating it.
let config = { token: 'abc123' };
config.token &&= config.token.trim(); // truthy → trimmed and reassigned
config.missing &&= 'never set'; // undefined → left untouched
console.log(config); // { token: 'abc123' }Each operator also short-circuits: it only evaluates and assigns the right-hand side when the condition requires it, so side effects on the right are skipped when the assignment doesn't happen.
Real-World Uses
The ?? operator shines anywhere a value might legitimately be missing while 0 or '' should be respected. Typical scenarios include reading configuration, defaulting optional function parameters, and pulling fields from API responses.
// 1. Default options merged with user input
function createButton(options) {
let label = options.label ?? 'Submit';
let count = options.count ?? 0; // 0 stays 0, never becomes a default
return { label, count };
}
// 2. Reading a possibly-missing API field
let response = { data: { user: { nickname: null } } };
let name = response.data.user.nickname ?? 'Guest';
console.log(name); // 'Guest'It pairs especially well with optional chaining (?.). Optional chaining safely returns undefined when part of a path is missing, and ?? then supplies the fallback in one clean line:
let city = user?.address?.city ?? 'Unknown';This reads as: "Use the user's city if the whole chain exists, otherwise use 'Unknown'." For deciding which of two paths to take based on a condition, the conditional (ternary) operator is still the better tool — ?? is specifically about supplying defaults for nullish values.
Browser support: ?? is part of ES2020 and the logical assignment operators (??=, ||=, &&=) arrived in ES2021. All modern browsers and Node.js 14+ support them. If you must target very old environments, a transpiler like Babel can compile them down.
Summary
??returns the right operand only when the left isnullorundefined; otherwise it returns the left.- Prefer
??over||for defaults when0,'', orfalseare valid values. ??has low precedence — group with parentheses, and never place it directly next to&&or||without parentheses (that is aSyntaxError).??=,||=, and&&=assign conditionally: on nullish, on falsy, and on truthy respectively.- Combine
??with optional chaining (?.) to read possibly-missing data and default it in a single expression.