The nullish coalescing operator ?? returns its right side only when the left side is null or undefined. Any other value, including 0, "" and false, is kept.
console.log(null ?? "default"); // → default
console.log(undefined ?? "default"); // → default
console.log(0 ?? "default"); // → 0
console.log("" ?? "default"); // →
console.log(false ?? "default"); // → false
Why it exists
Before ??, people used || for defaults. That replaces every falsy value:
const settings = { volume: 0, title: "", darkMode: false };
console.log(settings.volume || 50); // → 50
console.log(settings.volume ?? 50); // → 0
console.log(settings.title || "Untitled"); // → Untitled
console.log(settings.title ?? "Untitled"); // →
console.log(settings.darkMode ?? true); // → false
If the user turned the volume to 0, or deliberately left the title empty, or switched dark mode off, those are real choices. ?? respects them.
??= (nullish assignment)
??= assigns only if the variable is null or undefined.
const options = { retries: 0 };
options.retries ??= 3; // stays 0
options.timeout ??= 5000; // was missing, so it is set
console.log(options); // → { retries: 0, timeout: 5000 }
Mixing with || and &&
You cannot mix ?? directly with || or && without parentheses. It is a syntax error, to stop confusing precedence:
const x = a ?? b || c; // SyntaxError
const y = (a ?? b) || c; // fine
Use it with optional chaining
?? is most often paired with ?. to read something that may not exist, and fall back to a default. See Optional Chaining.
const user = {};
const city = user.address?.city ?? "Unknown";
console.log(city); // → Unknown
The rule
?? when 0, "" or false are valid values. Use || when any falsy value should trigger the fallback.