W3docs

JavaScript Optional Chaining (?.)

Learn the JavaScript optional chaining operator (?.) for safely accessing nested object properties and calling possibly-undefined methods without errors.

The optional chaining operator ?. is a short, safe way to read a value deep inside a chain of connected objects when one of the links in that chain might not exist. Instead of throwing an error, it simply stops and returns undefined. This chapter walks through the problem it solves, the three forms it takes, and the few rules you need to use it correctly.

The Problem: Reading Missing Properties

Imagine you have a user object, and you want to read the city from a nested address object. If address is missing, accessing a property on it throws an error:

let user = {}; // a user without an address

console.log(user.address.city);
// TypeError: Cannot read properties of undefined (reading 'city')

The reason is that user.address is undefined, and trying to read .city from undefined is not allowed. This is a common situation when data comes from an API, a form, or a database where some fields are optional.

Before ?. existed, developers worked around this with && chains or nested checks. These work, but they are verbose and repeat the property names:

let user = {};

// The old way with the && operator
let city = user && user.address && user.address.city;
console.log(city); // undefined

// Or with an even longer ternary
let city2 = user ? (user.address ? user.address.city : undefined) : undefined;
console.log(city2); // undefined

How Optional Chaining Works

The optional chaining operator ?. stops the evaluation if the value before it is null or undefined, and returns undefined instead of throwing. This behavior is called short-circuiting.

Here is the same lookup, now safe and readable:

javascript— editable

When user.address is undefined, the expression user?.address?.city quietly returns undefined. When the data is present, the chain reads all the way through to city.

Note

?. treats only null and undefined as "missing". Other falsy values such as 0, '' (empty string), or false are real values, so the chain continues normally through them.

It Only Guards the Value to Its Left

This is the most important rule, and the one beginners get wrong most often. The ?. checks only the value immediately to its left, not the whole chain.

Consider a?.b.c:

  • If a is null or undefined, the whole expression short-circuits and returns undefined.
  • But if a exists and b is null or undefined, then .c is still a plain access — and it throws.
let a = { b: null };

console.log(a?.b);    // null — fine, a exists
console.log(a?.b.c);  // TypeError: Cannot read properties of null (reading 'c')

The fix is to place ?. at every spot where a value may legitimately be absent:

let a = { b: null };

console.log(a?.b?.c); // undefined — no error

So the rule is simple: put ?. directly after each value that might not be there, not just at the start of the chain.

Short-Circuiting Stops the Whole Chain

When the part before ?. is null or undefined, the rest of the expression is not evaluated at all. This includes any function calls and any further property accesses that come after it.

javascript— editable

This is a useful guarantee: nothing after a missing link gets a chance to run or cause side effects.

The Three Forms of Optional Chaining

?. is not an operator on its own — it is a syntax construct that comes in three forms, one for each way of reaching into a value.

?. for Property Access

Use obj?.prop to read a property when obj might be null or undefined.

let user = { name: 'John' };

console.log(user?.name);    // John
console.log(user?.surname); // undefined (key missing, but no error)

?.() for Calling Methods

Use obj.method?.() to call a method only if it exists. This is handy when an object may or may not implement a given method.

javascript— editable

If greet is not a function (because it is missing), ?.() skips the call and returns undefined instead of throwing TypeError: greet is not a function.

?.[] for Dynamic Keys

Use obj?.[key] when you read a property with bracket notation — for example, a dynamic key stored in a variable.

let user = { name: 'Alice' };
let key = 'name';

console.log(user?.[key]); // Alice

let nobody = null;
console.log(nobody?.[key]); // undefined (no error)

Optional Chaining Is for Reading, Not Writing

You can use ?. to read a value, and even to delete a property safely. But you cannot use it on the left side of an assignment.

let user = null;

// Reading is fine
console.log(user?.name); // undefined

// Deleting is fine — delete is skipped if user is null
delete user?.name; // no error

// Assignment does NOT work — this is a syntax error
// user?.name = 'John'; // SyntaxError

The reason is that there is nothing meaningful to assign to when the left side is missing, so the language does not allow it.

Don't Overuse Optional Chaining

?. is a precise tool: use it only where the value to its left is genuinely optional. Reaching for it everywhere is a mistake, because it can hide real bugs.

For example, if you misspell a property name, ?. will silently return undefined instead of letting you notice the problem:

let user = { name: 'John' };

console.log(user?.nmae); // undefined — typo hidden, no error to alert you
Warning

If a variable like user must always exist (for example, it is a required argument), access it directly with user.address?.city, not user?.address?.city. That way, a genuinely missing user still throws an error early, which helps you catch bugs instead of masking them.

Pairing With Nullish Coalescing

Optional chaining returns undefined when a link is missing, which pairs perfectly with the nullish coalescing operator ?? to supply a default value.

javascript— editable

Here user?.name evaluates to undefined, and ?? then steps in to provide the fallback 'Anonymous'. This combination is one of the most common real-world uses of ?..

Browser Support

Optional chaining is part of the ES2020 specification. It is supported in all modern browsers (Chrome, Firefox, Safari, and Edge) and in Node.js 14 and later, so you can use it without a transpiler in current environments. To go deeper on the values it checks against, see JavaScript data types and object methods and this.

Test Your Knowledge

Practice
What does user?.address?.city return when user is undefined?
What does user?.address?.city return when user is undefined?
Practice
In the expression a?.b.c, when a exists but b is null, what happens?
In the expression a?.b.c, when a exists but b is null, what happens?
Practice
Which statements about the optional chaining operator are correct?
Which statements about the optional chaining operator are correct?
Was this page helpful?