v145 · Web APIs · expires vs maxAge
expires vs maxAge Comparison
The Cookie Store API originally only accepted an absolute expires date. Chrome 145 adds the maxAge shorthand — a relative number of seconds. This comparison shows why maxAge is simpler, more robust, and matches the semantics of the Max-Age cookie attribute that servers use.
Background: Both the classic
document.cookie string and the Set-Cookie HTTP header support both Max-Age (relative) and Expires (absolute). The Cookie Store API started with only expires (absolute); Chrome 145 adds maxAge (relative) to achieve parity.
setting a 1-hour cookie
Before Chrome 145 — expires (absolute)
// Must compute a Date object
const ONE_HOUR_MS = 60 * 60 * 1000;
await cookieStore.set({
name: 'session',
value: 'abc',
expires: new Date(Date.now() + ONE_HOUR_MS),
});
- ✗ Requires
Date.now()arithmetic - ✗ Units: milliseconds (non-obvious)
- ✗ Vulnerable to client clock skew if the date is far future
- ✗ Absolute timestamp stored in cookie; browser converts to Max-Age internally
Chrome 145+ — maxAge (relative)
// Just pass the duration in seconds
await cookieStore.set({
name: 'session',
value: 'abc',
maxAge: 3600, // 1 hour
});
- ✓ Seconds — intuitive, matches HTTP Max-Age
- ✓ No arithmetic or Date objects needed
- ✓ Relative — immune to client clock drift
- ✓ Matches
document.cookie = "name=val; Max-Age=3600"semantics
common durations
// Session cookie (no expiry — deleted when browser closes)
await cookieStore.set({ name: 'temp', value: 'x' });
// 5 minutes (CSRF token)
await cookieStore.set({ name: 'csrf', value: token, maxAge: 5 * 60 });
// 1 hour
await cookieStore.set({ name: 'session', value: id, maxAge: 60 * 60 });
// 1 day
await cookieStore.set({ name: 'pref', value: theme, maxAge: 24 * 60 * 60 });
// 30 days
await cookieStore.set({ name: 'auth', value: jwt, maxAge: 30 * 24 * 60 * 60 });
// 1 year (effectively "permanent")
await cookieStore.set({ name: 'id', value: uid, maxAge: 365 * 24 * 60 * 60 });
// Delete a cookie (maxAge: 0 — browser expires it immediately)
await cookieStore.set({ name: 'old', value: '', maxAge: 0 });
// Or use the dedicated delete:
await cookieStore.delete('old');
maxAge vs expires precedence
// If BOTH are specified: maxAge takes precedence (per HTTP spec)
await cookieStore.set({
name: 'test',
value: 'x',
maxAge: 3600, // 1 hour
expires: new Date(Date.now() + 86400000), // 1 day (ignored)
});
// Cookie lives for 1 hour — maxAge wins
see also
- maxAge Demo — interactive cookie setter
- ChromeStatus entry
- MDN — CookieStore.set()
scenario focus
Select a scenario to focus its rendered example and summary.