Nullish Coalescing

The ?? operator — defaults that respect zero, empty strings, and false.

Basics

?? returns the right side only for null/undefined.

// ?? — nullish coalescing operator:
// Returns RIGHT side if LEFT is null or undefined
// Returns LEFT side for everything else

null ?? "default";      // "default"
undefined ?? "default"; // "default"

// These are NOT nullish — left side is returned:
0 ?? "default";         // 0
"" ?? "default";        // ""
false ?? "default";     // false
NaN ?? "default";       // NaN

// Think of it as: "use this value, unless it's missing"
const name = user.name ?? "Anonymous";
const count = response.total ?? 0;
const enabled = settings.darkMode ?? true;

Nullish = null or undefined

Only these two values trigger the default. Zero, empty string, false, and NaN are all valid values that ?? preserves.

vs || (OR)

The key difference: what triggers the fallback.

// || triggers fallback for ALL falsy values:
0 || 42;          // 42  (0 is falsy)
"" || "default";  // "default" (empty string is falsy)
false || true;    // true (false is falsy)
null || "backup"; // "backup"

// ?? triggers fallback ONLY for null/undefined:
0 ?? 42;          // 0  ← preserves zero!
"" ?? "default";  // "" ← preserves empty string!
false ?? true;    // false ← preserves false!
null ?? "backup"; // "backup"

|| catches all falsy values (0, '', false, null, undefined, NaN). ?? only catches null and undefined.

1 / 2
Valuex || "fb"x ?? "fb"
null"fb""fb"
undefined"fb""fb"
0"fb"0
"""fb"""
false"fb"false
"hi""hi""hi"

??= Assignment

Assign only if the variable is null/undefined.

// Nullish coalescing assignment (??=):
// Assigns only if the left side is null/undefined

let name = null;
name ??= "Anonymous";
// name = "Anonymous" (was null)

let count = 0;
count ??= 10;
// count = 0 (was NOT null/undefined, so unchanged!)

// Equivalent to:
// x ??= y  →  x = x ?? y  →  if (x == null) x = y;

// Useful for lazy initialization:
function getCache() {
  this.cache ??= {};        // create once
  this.cache.hits ??= 0;   // init counter once
  return this.cache;
}

// Compare with other assignment operators:
let a = null;
a ||= "default"; // assigns if falsy (0, "", false, null, undefined)
a &&= "value";   // assigns if truthy
a ??= "default"; // assigns if null/undefined ONLY

With ?.

The perfect pair — safe access + safe defaults.

// ?. + ?? = safe access with fallback:
const theme = user?.settings?.theme ?? "light";
const avatar = profile?.images?.avatar ?? "/default.png";
const count = response?.data?.items?.length ?? 0;

// Without this combo (old verbose way):
const theme = user && user.settings && user.settings.theme
  ? user.settings.theme
  : "light";

// Real-world API handling:
async function getUser(id) {
  const res = await fetch(`/api/users/${id}`);
  const data = await res.json();
  
  return {
    name: data?.name ?? "Unknown",
    email: data?.email ?? null,
    avatar: data?.profile?.avatar?.url ?? "/placeholder.png",
    role: data?.permissions?.role ?? "viewer",
    lastLogin: data?.activity?.lastLogin ?? "Never",
  };
}

// DOM with fallback:
const title = document.querySelector("h1")?.textContent ?? "Untitled";
const width = element?.getBoundingClientRect()?.width ?? 0;

Patterns

Common patterns with nullish coalescing.

// 1. Configuration with defaults:
function createServer(options) {
  const port = options?.port ?? 3000;
  const host = options?.host ?? "localhost";
  const debug = options?.debug ?? false;
  // port: 0 is valid, debug: false is valid
}

// 2. Chaining with ??:
const value = primary ?? secondary ?? tertiary ?? "fallback";
// First non-nullish value wins

// 3. Form values (empty string is valid):
const search = input.value ?? "";
// Only defaults if value is somehow null/undefined
// Preserves "" (user cleared the field intentionally)

// 4. Numeric defaults:
const timeout = config.timeout ?? 5000;
const retries = config.retries ?? 3;
const delay = config.delay ?? 0; // 0 is preserved!

// ⚠️ Cannot mix with || or && without parentheses:
// a ?? b || c  → SyntaxError!
// a || b ?? c  → SyntaxError!
// Must use parens:
(a ?? b) || c  // ✓
a ?? (b || c)  // ✓

FAQ

Common questions about nullish coalescing.