Runtime · Data & Storage
Cookies
Use Bun's native APIs for working with HTTP cookies
Bun provides two native APIs for working with HTTP cookies: Bun.Cookie and Bun.CookieMap. They parse, generate, and manipulate cookies in HTTP requests and responses.
CookieMap class
Bun.CookieMap is a Map-like collection of cookies. It implements Iterable, so it works with for...of loops and the other iteration methods.
// Empty cookie map
const cookies = new Bun.CookieMap();
// From a cookie string
const cookies1 = new Bun.CookieMap("name=value; foo=bar");
// From an object
const cookies2 = new Bun.CookieMap({
session: "abc123",
theme: "dark",
});
// From an array of name/value pairs
const cookies3 = new Bun.CookieMap([
["session", "abc123"],
["theme", "dark"],
]);
In HTTP servers
In Bun's HTTP server, the cookies property on the request object (in routes) is an instance of CookieMap:
const server = Bun.serve({
routes: {
"/": req => {
// Access request cookies
const cookies = req.cookies;
// Get a specific cookie
const sessionCookie = cookies.get("session");
if (sessionCookie != null) {
console.log(sessionCookie);
}
// Check if a cookie exists
if (cookies.has("theme")) {
// ...
}
// Set a cookie, it will be automatically applied to the response
cookies.set("visited", "true");
return new Response("Hello");
},
},
});
console.log("Server listening at: " + server.url);
Methods
get(name: string): string | null
Retrieves a cookie by name. Returns null if the cookie doesn't exist.
// Get by name
const cookie = cookies.get("session");
if (cookie != null) {
console.log(cookie);
}
has(name: string): boolean
Checks if a cookie with the given name exists.
// Check if cookie exists
if (cookies.has("session")) {
// Cookie exists
}
set(name: string, value: string, options?: CookieInit): void
set(options: CookieInit): void
set(cookie: Cookie): void
Adds or updates a cookie in the map. Cookies default to { path: "/", sameSite: "lax" }.
// Set by name and value
cookies.set("session", "abc123");
// Set using options object
cookies.set({
name: "theme",
value: "dark",
maxAge: 3600,
secure: true,
});
// Set using Cookie instance
const cookie = new Bun.Cookie("visited", "true");
cookies.set(cookie);
delete(name: string): void
delete(options: CookieStoreDeleteOptions): void
delete(name: string, options: Omit<CookieStoreDeleteOptions, "name">): void
Removes a cookie from the map. When applied to a Response, the deletion adds a cookie with an empty string value and an expiry date in the past. The browser only deletes the cookie if the domain and path match the ones it was created with.
// Delete by name using default domain and path.
cookies.delete("session");
// Delete with domain/path options.
cookies.delete({
name: "session",
domain: "example.com",
path: "/admin",
});
toJSON(): Record<string, string>
Converts the cookie map to a serializable format.
const json = cookies.toJSON();
toSetCookieHeaders(): string[]
Returns an array of values for Set-Cookie headers that apply all cookie changes.
Use this with HTTP servers other than Bun.serve(). In Bun.serve(), you don't need to call it: Bun automatically applies any changes you make to the req.cookies map to the response headers.
import { createServer } from "node:http";
import { CookieMap } from "bun";
const server = createServer((req, res) => {
const cookieHeader = req.headers.cookie || "";
const cookies = new CookieMap(cookieHeader);
cookies.set("view-count", Number(cookies.get("view-count") || "0") + 1);
cookies.delete("session");
res.writeHead(200, {
"Content-Type": "text/plain",
"Set-Cookie": cookies.toSetCookieHeaders(),
});
res.end(`Found ${cookies.size} cookies`);
});
server.listen(3000, () => {
console.log("Server running at http://localhost:3000/");
});
toCookieHeader(): string
Returns the value of a request Cookie header for the cookies in the map, like "session=abc123; theme=dark". It is the inverse of new CookieMap(header): values are percent-encoded, and cookies that were deleted are left out.
const cookies = new Bun.CookieMap("session=abc123; note=a%20b");
cookies.set("theme", "dark");
cookies.delete("session");
cookies.toCookieHeader(); // => "theme=dark; note=a%20b"
CookieMap.fromSetCookie(headers: string | string[]): CookieMap
Creates a map from the Set-Cookie headers of a response, for example to carry cookies from one request to the next. Later headers replace earlier ones with the same name, and a header that expires its cookie (Max-Age of 0 or less, or a past Expires) removes it. The map keeps the attributes of each cookie, so toSetCookieHeaders() returns the headers again.
const response = await fetch("https://example.com/login");
const jar = Bun.CookieMap.fromSetCookie(response.headers.getSetCookie());
await fetch("https://example.com/account", {
headers: { cookie: jar.toCookieHeader() },
});
The map has no notion of domain or path. To keep cookies per site, or in a file, use bun cookie.
Iteration
CookieMap provides several methods for iteration:
// Iterate over [name, cookie] entries
for (const [name, value] of cookies) {
console.log(`${name}: ${value}`);
}
// Using entries()
for (const [name, value] of cookies.entries()) {
console.log(`${name}: ${value}`);
}
// Using keys()
for (const name of cookies.keys()) {
console.log(name);
}
// Using values()
for (const value of cookies.values()) {
console.log(value);
}
// Using forEach
cookies.forEach((value, name) => {
console.log(`${name}: ${value}`);
});
Properties
size: number
Returns the number of cookies in the map.
console.log(cookies.size); // Number of cookies
Cookie class
Bun.Cookie represents an HTTP cookie with its name, value, and attributes.
import { Cookie } from "bun";
// Create a basic cookie
const cookie = new Bun.Cookie("name", "value");
// Create a cookie with options
const secureSessionCookie = new Bun.Cookie("session", "abc123", {
domain: "example.com",
path: "/admin",
expires: new Date(Date.now() + 86400000), // 1 day
httpOnly: true,
secure: true,
sameSite: "strict",
});
// Parse from a cookie string
const parsedCookie = new Bun.Cookie("name=value; Path=/; HttpOnly");
// Create from an options object
const objCookie = new Bun.Cookie({
name: "theme",
value: "dark",
maxAge: 3600,
secure: true,
});
Constructors
// Basic constructor with name/value
new Bun.Cookie(name: string, value: string);
// Constructor with name, value, and options
new Bun.Cookie(name: string, value: string, options: CookieInit);
// Constructor from cookie string
new Bun.Cookie(cookieString: string);
// Constructor from cookie object
new Bun.Cookie(options: CookieInit);
Properties
cookie.name; // string - Cookie name
cookie.value; // string - Cookie value
cookie.domain; // string | null - Domain scope (null if not specified)
cookie.path; // string - URL path scope (defaults to "/")
cookie.expires; // Date | undefined - Expiration date
cookie.secure; // boolean - Require HTTPS
cookie.sameSite; // "strict" | "lax" | "none" - SameSite setting
cookie.partitioned; // boolean - Whether the cookie is partitioned (CHIPS)
cookie.maxAge; // number | undefined - Max age in seconds
cookie.httpOnly; // boolean - Accessible only via HTTP (not JavaScript)
cookie.prefix; // "__Host-" | "__Secure-" | null - Name prefix (read-only)
The domain is case-insensitive: Bun stores it in lowercase, so domain: "Example.COM" becomes "example.com".
Methods
isExpired(): boolean
Checks if the cookie has expired. When both maxAge and expires are set, maxAge takes precedence, as required by RFC 6265.
// Expired cookie (Date in the past)
const expiredCookie = new Bun.Cookie("name", "value", {
expires: new Date(Date.now() - 1000),
});
console.log(expiredCookie.isExpired()); // true
// Valid cookie (Using maxAge instead of expires)
const validCookie = new Bun.Cookie("name", "value", {
maxAge: 3600, // 1 hour in seconds
});
console.log(validCookie.isExpired()); // false
// A non-positive maxAge expires the cookie immediately
const deletedCookie = new Bun.Cookie("name", "value", { maxAge: 0 });
console.log(deletedCookie.isExpired()); // true
// Session cookie (no expiration)
const sessionCookie = new Bun.Cookie("name", "value");
console.log(sessionCookie.isExpired()); // false
hasValidPrefix(): boolean
Names that start with __Secure- or __Host- (matched without regard to case) must meet the rules of RFC 6265bis, section 4.1.3, or browsers drop the cookie without an error. hasValidPrefix() checks them:
| Prefix | Requires |
|---|---|
__Secure- | secure |
__Host- | secure, path of /, and no domain |
A cookie without a prefix is always valid. cookie.prefix returns the prefix as "__Host-" or "__Secure-", or null.
new Bun.Cookie("__Host-id", "1").hasValidPrefix(); // false: not Secure
new Bun.Cookie("__Host-id", "1", { secure: true }).hasValidPrefix(); // true
new Bun.Cookie("__Host-id", "1", { secure: true, domain: "example.com" }).hasValidPrefix(); // false
Bun.Cookie.parse("__Secure-id=1; Secure; Path=/").prefix; // "__Secure-"
Bun does not change or reject a cookie for this; check it where a wrong cookie would otherwise go unnoticed.
serialize(): string
toString(): string
Returns a string representation of the cookie suitable for a Set-Cookie header.
const cookie = new Bun.Cookie("session", "abc123", {
domain: "example.com",
path: "/admin",
expires: new Date(Date.now() + 86400000),
secure: true,
httpOnly: true,
sameSite: "strict",
});
console.log(cookie.serialize());
// => "session=abc123; Domain=example.com; Path=/admin; Expires=Wed, 19 Mar 2025 15:03:26 GMT; Secure; HttpOnly; SameSite=Strict"
console.log(cookie.toString());
// => "session=abc123; Domain=example.com; Path=/admin; Expires=Wed, 19 Mar 2025 15:03:26 GMT; Secure; HttpOnly; SameSite=Strict"
toJSON(): CookieInit
Converts the cookie to a plain object suitable for JSON serialization.
const cookie = new Bun.Cookie("session", "abc123", {
secure: true,
httpOnly: true,
});
const json = cookie.toJSON();
// => {
// name: "session",
// value: "abc123",
// path: "/",
// secure: true,
// httpOnly: true,
// sameSite: "lax",
// partitioned: false
// }
// Works with JSON.stringify
const jsonString = JSON.stringify(cookie);
Static methods
Cookie.parse(cookieString: string): Cookie
Parses a cookie string into a Cookie instance.
const cookie = Bun.Cookie.parse("name=value; Path=/; Secure; SameSite=Lax");
console.log(cookie.name); // "name"
console.log(cookie.value); // "value"
console.log(cookie.path); // "/"
console.log(cookie.secure); // true
console.log(cookie.sameSite); // "lax"
Cookie.parse follows RFC 6265bis for the attributes: names are case-insensitive, the last occurrence of an attribute wins, Domain is lowercased, and Max-Age is accepted only as an integer (an optional - and digits, so Max-Age=3600abc and Max-Age=+60 are ignored and an earlier valid Max-Age stays). A Max-Age beyond the 64-bit range is clamped. Max-Age takes precedence over Expires in isExpired().
Cookie.from(name: string, value: string, options?: CookieInit): Cookie
Factory method to create a cookie.
const cookie = Bun.Cookie.from("session", "abc123", {
httpOnly: true,
secure: true,
maxAge: 3600,
});
Types
interface CookieInit {
name?: string;
value?: string;
domain?: string;
/** Defaults to '/'. To allow the browser to set the path, use an empty string. */
path?: string;
expires?: number | Date | string;
secure?: boolean;
/** Defaults to `lax`. */
sameSite?: CookieSameSite;
httpOnly?: boolean;
partitioned?: boolean;
maxAge?: number;
}
interface CookieStoreDeleteOptions {
name: string;
domain?: string | null;
path?: string;
}
interface CookieStoreGetOptions {
name?: string;
url?: string;
}
type CookieSameSite = "strict" | "lax" | "none";
class Cookie {
constructor(name: string, value: string, options?: CookieInit);
constructor(cookieString: string);
constructor(cookieObject?: CookieInit);
readonly name: string;
value: string;
domain: string | null;
path: string;
expires?: Date;
secure: boolean;
sameSite: CookieSameSite;
partitioned: boolean;
maxAge?: number;
httpOnly: boolean;
readonly prefix: "__Host-" | "__Secure-" | null;
isExpired(): boolean;
hasValidPrefix(): boolean;
serialize(): string;
toString(): string;
toJSON(): CookieInit;
static parse(cookieString: string): Cookie;
static from(name: string, value: string, options?: CookieInit): Cookie;
}
class CookieMap implements Iterable<[string, string]> {
constructor(init?: string[][] | Record<string, string> | string);
static fromSetCookie(headers: string | string[]): CookieMap;
get(name: string): string | null;
toSetCookieHeaders(): string[];
toCookieHeader(): string;
has(name: string): boolean;
set(name: string, value: string, options?: CookieInit): void;
set(options: CookieInit): void;
delete(name: string): void;
delete(options: CookieStoreDeleteOptions): void;
delete(name: string, options: Omit<CookieStoreDeleteOptions, "name">): void;
toJSON(): Record<string, string>;
readonly size: number;
entries(): IterableIterator<[string, string]>;
keys(): IterableIterator<string>;
values(): IterableIterator<string>;
forEach(callback: (value: string, key: string, map: CookieMap) => void): void;
[Symbol.iterator](): IterableIterator<[string, string]>;
}