JavaScript Optional Chaining: Complete Guide
Optional chaining (?.) safely accesses nested properties without crashing. Learn how it works on objects, arrays, and function calls.
Optional chaining (?.) lets you safely access deeply nested properties without crashing when something in the middle is null or undefined. Instead of throwing a type error, it short-circuits and returns undefined.
const user = null;
// Without optional chaining: crashes
// console.log(user.address.city); // TypeError: Cannot read properties of null
// With optional chaining: safe, returns undefined
console.log(user?.address?.city); // undefinedThis is the modern replacement for long chains of AND checks that were common before ES2020.
The Problem Optional Chaining Solves
Before optional chaining, accessing a nested property safely required checking every level:
// Old way: verbose and repetitive
const city = user && user.address && user.address.city;
// New way: same safety, cleaner syntax
const city = user?.address?.city;With the AND version, if any part of the chain is null or undefined, the expression short-circuits to undefined. Optional chaining does the same thing with less code.
Optional Chaining Variants
The ?. operator works in three places:
// 1. Property access
user?.profile?.name
// 2. Method calls
user?.getDisplayName?.()
// 3. Array access / dynamic keys
users?.[0]
item?.[dynamicKey]Property access
The most common use: accessing nested object properties without checking each level, which matters most when data comes from an API and some fields might be missing:
const response = {
data: {
user: null
}
};
console.log(response?.data?.user?.name); // undefined (safe, user is null)
console.log(response?.data?.user?.name ?? "Anonymous"); // "Anonymous" (with fallback)Each ?. checks the value to its left. If it is null or undefined, the expression returns undefined and the rest of the chain is skipped.
Method calls
Call a method only if it exists:
const obj = {
greet: () => "Hello!"
};
console.log(obj.greet?.()); // "Hello!" (method exists, called normally)
console.log(obj.farewell?.()); // undefined (method does not exist, no error)Without optional chaining, calling a method that does not exist would throw a type error and stop the script. With the optional call syntax, the call is simply skipped instead, and execution continues normally to whatever comes next.
Array access and dynamic keys
const users = null;
console.log(users?.[0]); // undefined (users is null)
console.log(users?.[0]?.name); // undefined (chain stops at users)
const key = "address";
const data = { address: "123 Main St" };
console.log(data?.[key]); // "123 Main St"How Short-Circuiting Works
The chain evaluates left to right. The first null or undefined stops the entire expression and returns undefined. No further property accesses are attempted, which is what prevents the error.
This short-circuit behavior also means any side effects on the right side of ?. will not run if the left side is nullish:
const obj = null;
obj?.computeExpensiveValue(); // computeExpensiveValue is never calledPractical Use Cases
Working with API responses
APIs often return partial data, and a field you expect to exist might be missing or null depending on server state. Optional chaining handles this gracefully:
async function fetchUserName(userId) {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
return data?.user?.profile?.displayName ?? "Unknown User";
}If the API returns a null user or a profile with no display name, the function returns "Unknown User" instead of crashing.
DOM element access
When an element might not exist on the page:
const modal = document.querySelector(".modal");
modal?.classList.add("visible");If the element is not in the DOM, the selector returns null, and optional chaining safely skips the class-list update instead of throwing an error and stopping the rest of the script.
Event handler access
function handleEvent(event) {
event?.preventDefault?.();
// process event...
}If event is null or if preventDefault is missing (unlikely in standard events, but common in custom event systems), the call is safely skipped.
What Optional Chaining Does Not Do
Optional chaining only protects against null and undefined. It does not protect against other errors:
const user = { address: "123 Main St" };
console.log(user?.address?.city); // undefined (no city property, but no error)
console.log(user?.address?.toUpperCase()); // "123 MAIN ST" (address is a string, method exists)If a property exists but is 0, an empty string, or false, optional chaining does not stop. It only stops on null and undefined.
To provide fallback values when the result is undefined, pair ?. with the nullish coalescing operator:
const city = user?.address?.city ?? "No city provided";Optional Chaining vs the && Pattern
| ?. (optional chaining) | && (logical AND) | |
|---|---|---|
| Stops on | null, undefined | Any falsy value |
| Result when stopped | undefined | The falsy value itself |
| Readability | Clean, obvious intent | Verbose, mechanical |
| Method calls | obj.method?.() | No direct equivalent |
The AND pattern also stops on 0, an empty string, and false, which can hide real values. Optional chaining is more precise. For more on how AND short-circuiting works, see the logical short-circuiting guide.
Rune AI
Key Insights
- ?. returns undefined if the left side is null or undefined, instead of throwing.
- Use ?. for properties (user?.address?.city), methods (obj?.method?.()), and arrays (arr?.[0]).
- ?. short-circuits: once it hits null/undefined, the rest of the chain is skipped.
- ?. does not protect against non-null values that are missing a property.
- Optional chaining is read-only. You cannot assign through ?..
- Combine ?. with ?? to provide a fallback value when the chain returns undefined.
Frequently Asked Questions
What happens if I use ?. on a value that is not null or undefined?
Can I use optional chaining on the left side of an assignment?
Does optional chaining work in all browsers?
Conclusion
Optional chaining (?.) is the safe way to access nested properties, array items, and function calls when something in the chain might be null or undefined. It short-circuits to undefined instead of throwing an error. Use it when working with API responses, user data, or any deeply nested structure where intermediate values are optional. It replaces long chains of && checks with a single ?. that is easier to read and write.
More in this topic
JavaScript While Loop Explained: A Complete Guide
A while loop repeats code as long as a condition stays true. Learn the syntax, see practical examples, and understand when a while loop is the right choice over a for loop.
JavaScript Loops Tutorial: for, while, do while
Loops let JavaScript repeat code without writing it twice. Learn the three core loop types, what each one does, and when to choose one over another.
How to Loop Through Arrays Using JS for Loops Guide
Looping through arrays is the most practical use of JavaScript for loops. Learn how to access each element by index, avoid off-by-one errors, and choose between for, for...of, and forEach.