Optional Chaining
This lesson explains Optional Chaining with clear examples, use cases, and best practices so you can use modern JavaScript confidently in real projects.
ES6+ Optional Chaining Overview
Optional chaining uses the ?. operator to safely access
nested properties, call methods, or read values from arrays without
throwing an error when an intermediate value is
null or undefined.
It is especially useful when working with API responses, user
profiles, configuration objects, and DOM elements that may not exist
yet.
| Feature | Description |
| Introduced In | ES2020 |
| Operator | ?. |
| Stops On | null or undefined |
| Returns | undefined when access cannot continue |
| Forms | Property, method, and bracket access |
| Common Uses | API data, nested objects, optional DOM access |
Basic Optional Chaining Example
const user = {
name: "Alex",
address: {
city: "Hyderabad"
}
};
console.log(user?.name);
console.log(user?.phone);
console.log(user?.address?.city);
console.log(user?.address?.zip);
If a property does not exist or an intermediate value is
null or undefined, optional chaining
returns undefined instead of throwing an error.
How Optional Chaining Works
JavaScript checks each step in the chain. If the current value is
not null or undefined, it continues. If
not, it stops immediately and returns
undefined.
| Step | Description | Example |
| Start Access | Begin with a possibly missing value. | user?.profile |
| Check Value | Is current value nullish? | null or undefined |
| Continue | Access the next property if safe. | ?.name |
| Short-Circuit | Stop and return undefined. | No runtime error |
| Add Fallback | Combine with ?? if needed. | ?? "Guest" |
Optional Property Chaining
const response = {
data: {
user: {
profile: {
theme: "dark"
}
}
}
};
const theme =
response?.data?.user?.profile?.theme;
const language =
response?.data?.user?.settings?.language;
console.log(theme);
console.log(language);
Deep property access becomes much safer when any level of the object
tree may be missing.
Optional Method Chaining
const api = {
getUser() {
return { name: "Sam" };
}
};
console.log(
api.getUser?.()?.name
);
console.log(
api.deleteUser?.()
);
const emptyApi = null;
console.log(
emptyApi?.getUser?.()
);
Use ?.() to call a method only if the object and method
exist. This prevents errors like
Cannot read properties of null.
Optional Bracket Access
const settings = {
preferences: {
theme: "dark",
language: "en"
}
};
const key = "theme";
console.log(
settings?.preferences?.[key]
);
console.log(
settings?.preferences?.["fontSize"]
);
Optional chaining also works with bracket notation, which is useful
when property names come from variables.
Optional Array Access
const orders = {
items: [
{ id: 1, name: "Keyboard" },
{ id: 2, name: "Mouse" }
]
};
console.log(
orders?.items?.[0]?.name
);
console.log(
orders?.items?.[5]?.name
);
const emptyCart = null;
console.log(
emptyCart?.items?.[0]?.name
);
You can safely access array indexes with optional chaining when the
array itself may not exist.
API Response Example
async function showUserEmail() {
const response =
await fetch("/api/user");
const data =
await response.json();
const email =
data?.user?.contact?.email;
console.log(email ?? "No email found");
}
showUserEmail();
Optional chaining is very common in frontend apps where API payloads
vary and nested fields may be absent.
DOM Access Example
const button =
document.querySelector(
".submit-btn"
);
button?.addEventListener?.(
"click",
() => {
console.log("Submitted");
}
);
const title =
document
?.querySelector(".hero-title")
?.textContent;
console.log(title);
Optional chaining helps when DOM elements may not exist on every page
or when scripts run before the page fully loads.
Optional Chaining with Nullish Coalescing
const profile = {
settings: {
theme: ""
}
};
const theme =
profile?.settings?.theme ?? "light";
const language =
profile?.settings?.language ?? "en";
console.log(theme);
console.log(language);
Pair ?. with ?? to provide fallback values
only when the result is null or
undefined.
Old Pattern vs Optional Chaining
const user = {
address: {
city: "Pune"
}
};
// Old pattern
const oldCity =
user &&
user.address &&
user.address.city;
// Modern pattern
const newCity =
user?.address?.city;
console.log(oldCity);
console.log(newCity);
Optional chaining replaces long chains of
&& checks with a shorter and more readable
syntax.
Optional Chaining vs Logical AND
| Feature | ?. | && |
| Purpose | Safe property or method access | Truthy checks and short-circuiting |
| Stops On | null or undefined | Any falsy value |
| Return Value | Accessed value or undefined | Last evaluated operand |
| Best For | Nested object access | Conditional logic |
Common Optional Chaining Use Cases
- Reading nested API response data safely.
- Accessing optional user profile fields.
- Calling methods that may not exist on an object.
- Working with partially loaded application state.
- Handling optional DOM elements and event listeners.
- Reading config values from deep settings objects.
- Preventing runtime errors in defensive UI code.
Optional Chaining Best Practices
- Use optional chaining when intermediate values may be missing.
- Combine with
?? when you need fallback defaults. - Prefer
?. over long && chains for readability. - Do not use optional chaining to hide bad data design everywhere.
- Validate critical required fields explicitly when needed.
- Use optional method calls only when the method may not exist.
- Keep chains readable instead of making them excessively long.
Common Optional Chaining Mistakes
- Using
?. when a value is actually required. - Expecting optional chaining to provide default values by itself.
- Confusing optional chaining with nullish coalescing.
- Assuming it protects against all errors, including logic bugs.
- Overusing it on values that are always defined.
- Writing chains so long that debugging becomes difficult.
- Forgetting that it returns
undefined, not null.
Key Takeaways
- Optional chaining uses the
?. operator for safe access. - It short-circuits on
null or undefined. - It works with properties, methods, brackets, and arrays.
- It helps prevent common nested access runtime errors.
- Pair it with
?? when fallback values are needed.
Pro Tip
For optional nested values with defaults, combine both operators:
user?.profile?.name ?? "Guest".