Cookies: document.cookie
In the world of web development, managing data effectively is crucial. One of the fundamental ways to handle data on the client side is through the use of
Cookies are small pieces of data (max ~4 KB each) that a site stores in the browser and that are automatically attached to every request sent to the same origin. That last part is what makes them different from other client-side storage: cookies travel to the server, so they are the classic mechanism for session identifiers, "remember me" tokens, and language or theme preferences the server needs to know about. This guide covers how to read, write, and delete cookies with document.cookie, the attributes that control their scope and lifetime, and when to reach for a different storage option instead.
How document.cookie works
document.cookie is a deceptively simple property. Reading it returns all cookies for the current document as one semicolon-separated string of name=value pairs. Writing to it sets one cookie at a time — and crucially, assigning to it does not overwrite the whole string. The browser parses your assignment and merges that single cookie into the existing set:
// Reading: returns everything as one string
document.cookie; // "theme=dark; lang=en; sessionId=abc123"
// Writing: adds/updates ONE cookie, leaves the rest intact
document.cookie = "username=John";The attributes you tack on (path, expires, Secure, …) are write-only — they configure the cookie but never come back when you read document.cookie. You only ever get name=value pairs back.
Creating a cookie
To create a cookie, assign a name=value string to document.cookie, optionally followed by ;-separated attributes. If the value contains spaces, semicolons, or other special characters, encode it with encodeURIComponent so it doesn't break parsing:
This creates a cookie named username with the value John Doe (encoded to handle the space), expiring on June 8, 2025, and accessible across the whole site (path=/).
Cookie attributes
Attributes are appended to the assignment string and control where the cookie is sent and how long it lives. The most important ones:
| Attribute | What it does |
|---|---|
path | Limits the cookie to a URL path prefix. path=/ (the usual choice) makes it site-wide; path=/admin scopes it to /admin and below. |
domain | Controls which hosts receive the cookie. Defaults to the current host only. domain=example.com shares it with every subdomain (app.example.com, shop.example.com). You can only set a domain you're currently on. |
expires | A Date in UTC string form (toUTCString()). After it passes, the browser drops the cookie. |
max-age | Lifetime in seconds from now — a simpler alternative to expires. max-age=0 deletes the cookie. |
Secure | Sends the cookie only over HTTPS. |
SameSite | Strict, Lax (default in modern browsers), or None — controls whether the cookie rides along with cross-site requests. |
Without expires or max-age, you get a session cookie that disappears when the browser closes.
Setting an expiry
Use expires for an absolute date or max-age for a relative lifetime in seconds. max-age is usually easier because you don't have to format a date:
This userSettings cookie expires 24 hours (86,400 seconds) after it's created.
Reading a specific cookie
Because document.cookie hands back every cookie in one string, getting a single value means parsing it. A robust helper prefixes the string with ; so the same split works for the first cookie as for any other:
If you need to walk every cookie, split on ; and parse each pair yourself:
Deleting a cookie
There's no "delete" command — you delete a cookie by re-setting it with an expiry in the past (or max-age=0). The catch that trips everyone up: you must use the same path and domain the cookie was created with, otherwise the browser treats it as a different cookie and leaves the original in place.
Setting expires=Thu, 01 Jan 1970 00:00:00 UTC achieves the same thing for browsers that prefer expires over max-age.
Securing cookies
When a cookie holds anything sensitive (a session token above all), the attributes matter as much as the value:
Secure— only send the cookie over HTTPS, so it can't leak over a plain HTTP connection.SameSite— control whether the cookie is attached to cross-site requests.Lax(the modern default) blocks it on most cross-site requests, mitigating CSRF;Strictis tightest;None(which requiresSecure) is for genuine cross-site use cases.HttpOnly— hides the cookie from JavaScript entirely, protecting session tokens from XSS theft. It cannot be set fromdocument.cookie; the server must send it via theSet-Cookieresponse header. That's why session cookies are typically server-managed.
On an HTTPS site, add Secure to every cookie. Never store passwords or other secrets in a cookie readable by JavaScript — anything you can read with document.cookie, a successful XSS attack can read too.
document.cookie = "sessionId=abc123; expires=Sat, 08 Jun 2025 12:00:00 UTC; path=/; Secure; SameSite=Lax";Cookies vs. localStorage
Cookies aren't the only client-side store, and for most data they aren't the best one. Reach for cookies only when the server needs the data on every request:
| Cookies | localStorage | |
|---|---|---|
| Sent to the server | Yes, on every request | No, stays in the browser |
| Capacity | ~4 KB per cookie | ~5–10 MB per origin |
| Lifetime | expires / max-age, else session | Until explicitly cleared |
| JS access | document.cookie (unless HttpOnly) | localStorage.getItem/setItem |
| Typical use | Session IDs, auth tokens, server-read prefs | UI state, caches, drafts |
If you just need to remember something on the client and the server never reads it, localStorage or sessionStorage is simpler and roomier; the Storage API covers it in depth. Because cookies are sent automatically with requests, they also interact with CORS rules — see cross-origin requests with Fetch for sending credentials across origins.
Conclusion
Cookies remain the standard way to share small pieces of state with the server — sessions, auth, and server-read preferences. Write them one at a time with document.cookie, scope them with path/domain, control their lifetime with expires/max-age, and lock them down with Secure, SameSite, and (server-side) HttpOnly. For larger, client-only data, prefer Web Storage instead.