Skip to main content

cookie vs tough-cookie vs set-cookie-parser: Cookie Handling in Node.js (2026)

·PkgPulse Team

TL;DR

cookie is the basic cookie parser/serializer — parses Cookie headers into objects, serializes name/value pairs with options (maxAge, path, secure), used by Express internally. tough-cookie is the full cookie jar implementation — stores cookies across requests, handles domain matching, path scoping, expiration, Set-Cookie parsing, used by got, axios, and testing tools. set-cookie-parser parses Set-Cookie response headers — extracts cookies from HTTP responses, handles multiple Set-Cookie headers, works with fetch and undici. In 2026: cookie for basic parsing/serializing, tough-cookie for cookie jar management (crawlers, testing), set-cookie-parser for reading Set-Cookie from responses.

Key Takeaways

  • cookie: ~30M weekly downloads — basic parse/serialize, used by Express, zero deps
  • tough-cookie: ~15M weekly downloads — full cookie jar, domain/path matching, RFC 6265
  • set-cookie-parser: ~5M weekly downloads — parses Set-Cookie headers from responses
  • Different scopes: cookie does parse/serialize, tough-cookie manages state, set-cookie-parser reads headers
  • cookie is the lowest level — just string manipulation
  • tough-cookie implements the full browser cookie algorithm

cookie — basic cookie parsing:

Parse cookies

import cookie from "cookie"

// Parse a Cookie header:
const cookies = cookie.parse("session=abc123; theme=dark; lang=en")
// → { session: "abc123", theme: "dark", lang: "en" }

// In an Express/Node.js handler:
function handler(req, res) {
  const cookies = cookie.parse(req.headers.cookie || "")
  const session = cookies.session
  const theme = cookies.theme ?? "light"
}

Serialize cookies

import cookie from "cookie"

// Create a Set-Cookie header value:
cookie.serialize("session", "abc123", {
  httpOnly: true,
  secure: true,
  sameSite: "strict",
  maxAge: 60 * 60 * 24 * 7,  // 7 days
  path: "/",
})
// → "session=abc123; Max-Age=604800; Path=/; HttpOnly; Secure; SameSite=Strict"

// Multiple cookies — set multiple headers:
const sessionCookie = cookie.serialize("session", "abc123", { httpOnly: true })
const themeCookie = cookie.serialize("theme", "dark", { maxAge: 31536000 })

res.setHeader("Set-Cookie", [sessionCookie, themeCookie])
import cookie from "cookie"

// All serialization options:
cookie.serialize("name", "value", {
  domain: ".pkgpulse.com",     // Domain scope
  path: "/api",                 // Path scope
  maxAge: 86400,                // Seconds until expiry
  expires: new Date("2026-12-31"),  // Absolute expiry
  httpOnly: true,               // No JavaScript access
  secure: true,                 // HTTPS only
  sameSite: "lax",              // CSRF protection: "strict" | "lax" | "none"
  priority: "high",             // "low" | "medium" | "high"
  partitioned: true,            // CHIPS (partitioned cookies)
})

tough-cookie — full cookie jar:

import { CookieJar, Cookie } from "tough-cookie"

// Create a cookie jar:
const jar = new CookieJar()

// Store cookies:
await jar.setCookie("session=abc123; Path=/; HttpOnly", "https://pkgpulse.com")
await jar.setCookie("theme=dark; Path=/; Max-Age=31536000", "https://pkgpulse.com")

// Retrieve cookies for a URL:
const cookies = await jar.getCookies("https://pkgpulse.com/api/packages")
// → [Cookie { key: "session", value: "abc123" }, Cookie { key: "theme", value: "dark" }]

// Get as Cookie header string:
const cookieString = await jar.getCookieString("https://pkgpulse.com/api/packages")
// → "session=abc123; theme=dark"

Domain and path matching

import { CookieJar } from "tough-cookie"

const jar = new CookieJar()

// Domain-scoped cookie:
await jar.setCookie(
  "tracking=xyz; Domain=.pkgpulse.com; Path=/",
  "https://www.pkgpulse.com"
)

// Available on subdomains:
await jar.getCookieString("https://api.pkgpulse.com")
// → "tracking=xyz"

await jar.getCookieString("https://pkgpulse.com")
// → "tracking=xyz"

// NOT available on different domain:
await jar.getCookieString("https://other-site.com")
// → ""

// Path-scoped:
await jar.setCookie("admin=true; Path=/admin", "https://pkgpulse.com")

await jar.getCookieString("https://pkgpulse.com/admin/users")
// → "tracking=xyz; admin=true"

await jar.getCookieString("https://pkgpulse.com/api")
// → "tracking=xyz"  (admin cookie not included)

With HTTP clients

import { CookieJar } from "tough-cookie"
import got from "got"

// Use with got:
const jar = new CookieJar()

// Login — jar stores the session cookie:
await got.post("https://api.pkgpulse.com/auth/login", {
  json: { email: "user@example.com", password: "..." },
  cookieJar: jar,
})

// Subsequent requests include the cookie automatically:
const response = await got("https://api.pkgpulse.com/api/me", {
  cookieJar: jar,
})
// Session cookie sent automatically
import { CookieJar, Cookie } from "tough-cookie"

const jar = new CookieJar()
await jar.setCookie(
  "session=abc; Path=/; HttpOnly; Secure; SameSite=Strict; Max-Age=3600",
  "https://pkgpulse.com"
)

// Inspect stored cookies:
const cookies = await jar.getCookies("https://pkgpulse.com")
const session = cookies[0]

session.key           // "session"
session.value         // "abc"
session.domain        // "pkgpulse.com"
session.path          // "/"
session.httpOnly      // true
session.secure        // true
session.sameSite      // "strict"
session.TTL()         // Time to live in ms
session.expiryDate()  // Date object

set-cookie-parser — parse Set-Cookie headers:

import setCookieParser from "set-cookie-parser"

// Parse Set-Cookie header(s):
const cookies = setCookieParser.parse([
  "session=abc123; Path=/; HttpOnly; Secure; SameSite=Strict",
  "theme=dark; Path=/; Max-Age=31536000",
])

// → [
//   { name: "session", value: "abc123", path: "/", httpOnly: true, secure: true, sameSite: "Strict" },
//   { name: "theme", value: "dark", path: "/", maxAge: 31536000 },
// ]

With fetch responses

import setCookieParser from "set-cookie-parser"

// Parse cookies from a fetch response:
const response = await fetch("https://api.pkgpulse.com/auth/login", {
  method: "POST",
  body: JSON.stringify({ email: "user@example.com" }),
})

// Get Set-Cookie headers:
const setCookieHeaders = response.headers.getSetCookie()
// → ["session=abc; Path=/; HttpOnly", "csrf=xyz; Path=/"]

const cookies = setCookieParser.parse(setCookieHeaders)
// → [{ name: "session", value: "abc", ... }, { name: "csrf", value: "xyz", ... }]

With undici/Node.js fetch

import setCookieParser from "set-cookie-parser"

// Node.js fetch (undici) returns combined Set-Cookie:
const response = await fetch("https://api.example.com/login", {
  method: "POST",
  body: JSON.stringify({ user: "test" }),
})

// Split combined header:
const combinedHeader = response.headers.get("set-cookie")
const cookies = setCookieParser.splitCookiesString(combinedHeader)
// → ["session=abc; HttpOnly", "theme=dark; Max-Age=86400"]

const parsed = setCookieParser.parse(cookies)

Map format

import setCookieParser from "set-cookie-parser"

// Parse as a map (keyed by cookie name):
const cookieMap = setCookieParser.parse(setCookieHeaders, {
  map: true,
})

// → {
//   session: { name: "session", value: "abc", httpOnly: true, ... },
//   theme: { name: "theme", value: "dark", maxAge: 31536000, ... },
// }

// Easy lookup:
const sessionValue = cookieMap.session?.value

Feature Comparison

Featurecookietough-cookieset-cookie-parser
Parse Cookie header
Serialize Set-Cookie
Parse Set-Cookie
Cookie jar
Domain matching
Path scoping
Expiration tracking
RFC 6265 compliantPartial
HTTP client integration✅ (got, axios)
TypeScript
Weekly downloads~30M~15M~5M

When to Use Each

Use cookie if:

  • Parsing Cookie request headers in Express/Node.js middleware
  • Serializing Set-Cookie response headers
  • Need basic cookie string manipulation
  • Building simple cookie middleware

Use tough-cookie if:

  • Building a crawler or scraper that needs cookie persistence
  • Testing authenticated API flows
  • Need automatic domain/path matching (browser-like behavior)
  • Using with HTTP clients (got, axios) for session management

Use set-cookie-parser if:

  • Reading Set-Cookie headers from fetch/undici responses
  • Need to extract cookies from HTTP responses
  • Building a proxy that needs to inspect Set-Cookie headers
  • Working with multiple Set-Cookie headers

Methodology

Download data from npm registry (weekly average, February 2026). Feature comparison based on cookie v0.7.x, tough-cookie v5.x, and set-cookie-parser v2.x.

Compare cookie handling and HTTP tooling on PkgPulse →

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.