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

scenario focus

Select a scenario to focus its rendered example and summary.