How HTTP Works

Cookie attribute

< Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2026 07:28:00 GMT

Expires

Learn how the Expires cookie attribute sets an absolute expiration date. Understand date formats, timezone handling, and when to use Expires vs Max-Age.

Reviewed 3 min readbeginner2 sourcesTry itMarkdown
Default if omitted
Session cookie (dropped when the browser session ends)
Accepts
An HTTP-date
Sent back to server
No: never echoed in the Cookie header
Spec
RFC 6265 §4.1.2.1, RFC 6265bis (draft)
On this page

TL;DR: Expires sets an absolute HTTP-date after which the browser discards the cookie. If Max-Age is also present it wins, browsers cap either one at about 400 days, and a date in the past deletes the cookie instantly, which is why copy-pasted example dates silently break.

What Expires does

Without Expires or Max-Age a cookie is a session cookie. Do not read that as “gone when the browser closes”: Chrome’s “Continue where you left off” and Firefox/Safari session restore bring session cookies back across restarts, so a session cookie is not a reliable short lifetime. Use an explicit lifetime for anything that must expire.

Set-Cookie: remember=7f3a9c; Expires=Fri, 15 Oct 2027 12:00:00 GMT; Path=/; Secure; HttpOnly; SameSite=Lax

The date uses the IMF-fixdate form of HTTP-date (RFC 9110 section 5.6.7): Day, DD Mon YYYY HH:MM:SS GMT. Always GMT, English day and month names. Browsers are lenient and also parse the older cookie date grammar from RFC 6265 section 5.1.1, but do not rely on it.

Dates in examples on this page are in the future relative to October 2026. If you copy an old snippet with a 2025 date, the browser receives an already-expired cookie and removes it, so the symptom is “Set-Cookie is in the response but the cookie never appears in DevTools”.

Precedence and limits

  • If Max-Age and Expires both appear, Max-Age takes precedence (RFC 6265bis section 5.5). Sending both for “compatibility” is only needed for very old clients such as IE 8 and earlier, which ignored Max-Age.
  • RFC 6265bis caps cookie lifetime at 400 days. Chrome enforces this: a larger Expires or Max-Age is clamped to 400 days from the time it is set. Other browsers have their own caps, for example Safari limits cookies written by JavaScript to 7 days under Intelligent Tracking Prevention in some contexts.
  • Expires is evaluated against the client’s clock. A device with a wrong clock may see the cookie as already expired. Max-Age avoids that.

Generating the date

// Express: both forms work; maxAge is milliseconds in Express
res.cookie('remember', token, { expires: new Date('2027-10-15T12:00:00Z'), httpOnly: true, secure: true })
res.cookie('remember', token, { maxAge: 30 * 24 * 60 * 60 * 1000, httpOnly: true, secure: true })

// Browser: document.cookie wants a UTC string
document.cookie = `theme=dark; Expires=${new Date(Date.now() + 365 * 864e5).toUTCString()}; Path=/; Secure; SameSite=Lax`
# Django: pass max_age (seconds) or a timezone-aware expires datetime
response.set_cookie('theme', 'dark', max_age=60 * 60 * 24 * 365, secure=True, samesite='Lax')
// PHP: 'expires' is a Unix timestamp, not a date string
setcookie('userId', '123', [
    'expires' => time() + 30 * 24 * 60 * 60,
    'path' => '/',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);

Send the same name, Path and Domain with a past date (or Max-Age=0). A mismatched Path or Domain creates a second cookie instead of deleting the first.

Set-Cookie: remember=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Path=/
res.clearCookie('remember', { path: '/' })

Troubleshooting

SymptomLikely cause
Cookie appears then vanishes immediatelyExpires in the past, or Max-Age=0/negative
Lifetime shorter than requestedBrowser cap (400 days in Chrome) or ITP limits on script-set cookies
Cookie lifetime differs per userClient clock skew with Expires; switch to Max-Age
Delete does nothingPath or Domain does not match the original cookie
Parsed date wrongLocal timezone name instead of GMT, or new Date('2027-10-15 12:00 PST') style strings; use ISO Z strings in JavaScript

Inspect what the server really sent:

curl -sI https://example.com/login | grep -i '^set-cookie'

Frequently asked questions

What is the Expires cookie attribute?

Expires sets an absolute date/time when the cookie expires. After this time, browsers delete the cookie. Without Expires or Max-Age, cookies are session cookies.

What format does Expires use?

An HTTP-date in GMT as defined in RFC 9110 section 5.6.7, for example Expires=Thu, 21 Oct 2027 07:28:00 GMT. If the date is already in the past when the browser receives it, the cookie is deleted immediately.

Should I use Expires or Max-Age?

Prefer Max-Age: it counts seconds from receipt, so it is immune to client clock skew, and when both are present Max-Age wins. Expires is still useful as a fallback for very old clients and for hard calendar deadlines.

How do I delete a cookie?

Set Expires to a past date or Max-Age=0. The browser will delete the cookie immediately. You must match the original Path and Domain.

Sources

  1. MDN Web Docs: Cookie Expiresdeveloper.mozilla.org
  2. RFC 6265bis (draft): Expires attribute and 400-day capdatatracker.ietf.org

Keep going

Browse /search