js-cookie、react-cookie、universal-cookie は、Web アプリケーションで HTTP Cookie を扱うための代表的なライブラリです。js-cookie はブラウザ環境に特化した軽量ライブラリであり、universal-cookie はサーバーサイドレンダリング(SSR)を含む万能な環境で動作するコアライブラリです。react-cookie は universal-cookie を基盤とし、React 専用のフックやコンテキストを提供して統合を簡素化します。これらはそれぞれ環境要件とフレームワーク依存性において明確な違いがあります。
Web 開発において Cookie の扱いは、認証状態の維持やユーザー設定の保存など重要な役割を果たします。js-cookie、react-cookie、universal-cookie はいずれもこの課題を解決しますが、動作環境と API デザインに大きな違いがあります。アーキテクチャ選定ミスは SSR 環境でのバグや不要な依存関係につながります。ここでは技術的な違いを深掘りします。
Cookie ライブラリを選ぶ際、最も重要な基準は「サーバーサイドで動作するか」です。
js-cookie はブラウザ環境に特化しています。
document.cookie に直接アクセスします。// js-cookie: ブラウザ専用
import Cookies from 'js-cookie';
// SSR 環境ではエラー発生(document が未定義)
const value = Cookies.get('session_id');
universal-cookie は名前通り、あらゆる環境で動作します。
document.cookie を使用します。// universal-cookie: 万能対応
import Cookies from 'universal-cookie';
// SSR: req/res オブジェクトを渡す
const cookies = new Cookies(req?.res);
const value = cookies.get('session_id');
// Client: 引数なしでインスタンス化
const clientCookies = new Cookies();
react-cookie は React 環境に最適化されています。
universal-cookie を使用しているため、SSR 対応可能です。CookieProvider のラップが必要です。// react-cookie: React 特化
import { useCookies } from 'react-cookie';
function Component() {
// SSR 対応済みフック
const [cookies] = useCookies(['session_id']);
const value = cookies.session_id;
}
ライブラリごとの API スタイルは、コードの書き方とテストのしやすさに影響します。
js-cookie は静的な関数を提供します。
// js-cookie: 静的メソッド
import Cookies from 'js-cookie';
// 取得
const user = Cookies.get('user');
// 設定(オプションをオブジェクトで渡す)
Cookies.set('user', 'alice', { expires: 7, path: '/' });
// 削除
Cookies.remove('user');
universal-cookie はクラスベースの API です。
// universal-cookie: クラスインスタンス
import Cookies from 'universal-cookie';
const cookies = new Cookies();
// 取得
const user = cookies.get('user');
// 設定(オプションを第 3 引数で渡す)
cookies.set('user', 'alice', { path: '/', maxAge: 600 });
// 削除
cookies.remove('user');
react-cookie は React フックを提供します。
// react-cookie: React フック
import { useCookies } from 'react-cookie';
function Component() {
// 監視する Cookie キーの配列を渡す
const [cookies, setCookie, removeCookie] = useCookies(['user']);
const handleLogin = () => {
setCookie('user', 'alice', { path: '/' });
};
return <div>{cookies.user}</div>;
}
React アプリケーションにおいて、Cookie の変更をどう状態管理に反映するかは重要な点です。
js-cookie は React 固有の機能を持ちません。
useEffect 内で手動で読み書きする必要があります。// js-cookie in React
import { useEffect, useState } from 'react';
import Cookies from 'js-cookie';
function Component() {
const [user, setUser] = useState(null);
useEffect(() => {
// 手動で読み込み
setUser(Cookies.get('user'));
}, []);
return <div>{user}</div>;
}
universal-cookie も同様に変化の検知は手動です。
// universal-cookie in React
import { useEffect, useState } from 'react';
import Cookies from 'universal-cookie';
const cookies = new Cookies();
function Component() {
const [user, setUser] = useState(null);
useEffect(() => {
setUser(cookies.get('user'));
}, []);
return <div>{user}</div>;
}
react-cookie は変更を自動で検知します。
setCookie を呼ぶと、関連するコンポーネントが更新されます。// react-cookie: 自動同期
import { useCookies } from 'react-cookie';
function Component() {
// Cookie 変更時に自動再レンダリング
const [cookies, setCookie] = useCookies(['user']);
return (
<button onClick={() => setCookie('user', 'bob')}>
{cookies.user}
</button>
);
}
セキュリティ設定(Secure, SameSite, HttpOnly)の扱いも比較ポイントです。
js-cookie は安全なデフォルトを持ちます。
// js-cookie: 安全な設定
Cookies.set('session', 'abc', {
secure: true,
sameSite: 'Strict',
path: '/'
});
universal-cookie は詳細な制御が可能です。
HttpOnly などを設定する際に有利です。// universal-cookie: 詳細制御
const cookies = new Cookies();
cookies.set('session', 'abc', {
httpOnly: true, // サーバー側で重要
secure: true,
sameSite: 'strict'
});
react-cookie は React 経由で設定を渡します。
HttpOnly な Cookie は React からは設定できない制約があります。// react-cookie: クライアント側設定
const [cookies, setCookie] = useCookies(['pref']);
// HttpOnly はクライアント側では設定不可
setCookie('pref', 'dark', { path: '/' });
| 特徴 | js-cookie | universal-cookie | react-cookie |
|---|---|---|---|
| 環境 | 🌐 ブラウザ専用 | 🌍 万能(SSR 対応) | ⚛️ React 環境(SSR 対応) |
| API | 🛠️ 静的関数 | 🏗️ クラスインスタンス | 🎣 React フック |
| 依存関係 | 🍃 なし | 📦 なし(コア) | 🔗 universal-cookie 依存 |
| 再レンダリング | ❌ 手動管理 | ❌ 手動管理 | ✅ 自動検知 |
| SSR 対応 | ❌ 非対応 | ✅ 対応 | ✅ 対応(Provider 必要) |
| サイズ感 | 🪶 軽量 | 📦 標準 | 📦 標準 + React 分 |
プロジェクトの要件に応じて、以下の基準で選定してください。
js-cookie は、Next.js や Nuxt などの SSR フレームワークを使わない、シンプルな SPA や静的サイトに向いています — 余計な依存関係を増やさず、ブラウザの機能だけをラップしたい場合に最適です。
universal-cookie は、React 以外を使用している場合や、ビジネスロジック層で Cookie 操作を共通化したい場合に選択してください — サーバーとクライアントで同じコードを動かす必要があるアーキテクチャで真価を発揮します。
react-cookie は、モダンな React アプリケーションで開発効率を最大化したい場合に推奨します — フックによる状態管理と SSR 対応を両立でき、認証フローやユーザー設定の実装を大幅に簡素化します。
結論として、React + SSR 環境なら react-cookie、React なし + SSR なら universal-cookie、それ以外なら js-cookie が適切な選択です。
純粋なクライアントサイドアプリケーションで動作し、SSR が必要ない場合に選択してください。依存関係を増やしたくない場合や、ブラウザの document.cookie を単純にラップするだけの軽量ソリューションが必要なプロジェクトに適しています。サーバーサイドでの Cookie 読み書きが必要ないシンプルなケースで最も有効です。
React アプリケーションを開発しており、フックやコンテキストを使って Cookie 状態を管理したい場合に選択してください。SSR 環境(Next.js など)でも動作する必要があり、React 固有の機能で開発体験を向上させたい場合に最適です。universal-cookie の機能を React 向けに最適化したパッケージです。
React 以外のフレームワークを使用しているか、フレームワークに依存しない汎用的な Cookie 管理ロジックが必要な場合に選択してください。SSR とクライアントサイドの両方で動作する必要があるが、React 固有の機能は不要なケースに適しています。react-cookie の内部コアとしても機能する信頼性の高いライブラリです。
A simple, lightweight JavaScript API for handling cookies
👉👉 If you're viewing this at https://github.com/js-cookie/js-cookie, you're reading the documentation for the main branch. View documentation for the latest release. 👈👈
JavaScript Cookie supports npm under the name js-cookie.
npm i js-cookie
The npm package has a module field pointing to an ES module variant of the library, mainly to provide support for ES module aware bundlers, whereas its browser field points to an UMD module for full backward compatibility.
Not all browsers support ES modules natively yet. For this reason the npm package/release provides both the ES and UMD module variant and you may want to include the ES module along with the UMD fallback to account for this:
Alternatively, include js-cookie via jsDelivr CDN.
Create a cookie, valid across the entire site:
Cookies.set('name', 'value')
Create a cookie that expires 7 days from now, valid across the entire site:
Cookies.set('name', 'value', { expires: 7 })
Create an expiring cookie, valid to the path of the current page:
Cookies.set('name', 'value', { expires: 7, path: '' })
Read cookie:
Cookies.get('name') // => 'value'
Cookies.get('nothing') // => undefined
Read all visible cookies:
Cookies.get() // => { name: 'value' }
Note: It is not possible to read a particular cookie by passing one of the cookie attributes (which may or may not have been used when writing the cookie in question):
Cookies.get('foo', { domain: 'sub.example.com' }) // `domain` won't have any effect...!
The cookie with the name foo will only be available on .get() if it's visible from where the
code is called; the domain and/or path attribute will not have an effect when reading.
Delete cookie:
Cookies.remove('name')
Delete a cookie valid to the path of the current page:
Cookies.set('name', 'value', { path: '' })
Cookies.remove('name') // fail!
Cookies.remove('name', { path: '' }) // removed!
IMPORTANT! When deleting a cookie and you're not relying on the default attributes, you must pass the exact same path and domain attributes that were used to set the cookie:
Cookies.remove('name', { path: '', domain: '.yourdomain.com' })
Note: Removing a nonexistent cookie neither raises any exception nor returns any value.
If there is any danger of a conflict with the namespace Cookies, the noConflict method will allow you to define a new namespace and preserve the original one. This is especially useful when running the script on third party sites e.g. as part of a widget or SDK.
// Assign the js-cookie api to a different variable and restore the original "window.Cookies"
var Cookies2 = Cookies.noConflict()
Cookies2.set('name', 'value')
Note: The .noConflict method is not necessary when using AMD or CommonJS, thus it is not exposed in those environments.
This project is RFC 6265 compliant. All special characters that are not allowed in the cookie-name or cookie-value are encoded with each one's UTF-8 Hex equivalent using percent-encoding.
The only character in cookie-name or cookie-value that is allowed and still encoded is the percent % character, it is escaped in order to interpret percent input as literal.
Please note that the default encoding/decoding strategy is meant to be interoperable only between cookies that are read/written by js-cookie. To override the default encoding/decoding strategy you need to use a converter.
Note: According to RFC 6265, your cookies may get deleted if they are too big or there are too many cookies in the same domain, more details here.
Cookie attribute defaults can be set globally by creating an instance of the api via withAttributes(), or individually for each call to Cookies.set(...) by passing a plain object as the last argument. Per-call attributes override the default attributes.
Define when the cookie will be removed. Value must be a Number which will be interpreted as days from time of creation or a Date instance. If omitted, the cookie becomes a session cookie.
To create a cookie that expires in less than a day, you can check the FAQ on the Wiki.
Default: Cookie is removed when the user closes the browser.
Examples:
Cookies.set('name', 'value', { expires: 365 })
Cookies.get('name') // => 'value'
Cookies.remove('name')
A String indicating the path where the cookie is visible.
Default: /
Examples:
Cookies.set('name', 'value', { path: '' })
Cookies.get('name') // => 'value'
Cookies.remove('name', { path: '' })
Note regarding Internet Explorer:
Due to an obscure bug in the underlying WinINET InternetGetCookie implementation, IE’s document.cookie will not return a cookie if it was set with a path attribute containing a filename.
(From Internet Explorer Cookie Internals (FAQ))
This means one cannot set a path using window.location.pathname in case such pathname contains a filename like so: /check.html (or at least, such cookie cannot be read correctly).
In fact, you should never allow untrusted input to set the cookie attributes or you might be exposed to a XSS attack.
A String indicating a valid domain where the cookie should be visible. The cookie will also be visible to all subdomains.
Default: Cookie is visible only to the domain or subdomain of the page where the cookie was created, except for Internet Explorer (see below).
Examples:
Assuming a cookie that is being created on site.com:
Cookies.set('name', 'value', { domain: 'subdomain.site.com' })
Cookies.get('name') // => undefined (need to read at 'subdomain.site.com')
Note regarding Internet Explorer default behavior:
Q3: If I don’t specify a DOMAIN attribute (for) a cookie, IE sends it to all nested subdomains anyway?
A: Yes, a cookie set on example.com will be sent to sub2.sub1.example.com.
Internet Explorer differs from other browsers in this regard.
(From Internet Explorer Cookie Internals (FAQ))
This means that if you omit the domain attribute, it will be visible for a subdomain in IE.
Either true or false, indicating if the cookie transmission requires a secure protocol (https).
Default: No secure protocol requirement.
Examples:
Cookies.set('name', 'value', { secure: true })
Cookies.get('name') // => 'value'
Cookies.remove('name')
A String, allowing to control whether the browser is sending a cookie along with cross-site requests.
Default: not set.
Note that more recent browsers are making "Lax" the default value even without specifiying anything here.
Examples:
Cookies.set('name', 'value', { sameSite: 'strict' })
Cookies.get('name') // => 'value'
Cookies.remove('name')
const api = Cookies.withAttributes({ path: '/', domain: '.example.com' })
Create a new instance of the api that overrides the default decoding implementation. All get methods that rely in a proper decoding to work, such as Cookies.get() and Cookies.get('name'), will run the given converter for each cookie. The returned value will be used as the cookie value.
Example from reading one of the cookies that can only be decoded using the escape function:
document.cookie = 'escaped=%u5317'
document.cookie = 'default=%E5%8C%97'
var cookies = Cookies.withConverter({
read: function (value, name) {
if (name === 'escaped') {
return unescape(value)
}
// Fall back to default for all other cookies
return Cookies.converter.read(value, name)
}
})
cookies.get('escaped') // 北
cookies.get('default') // 北
cookies.get() // { escaped: '北', default: '北' }
Create a new instance of the api that overrides the default encoding implementation:
Cookies.withConverter({
write: function (value, name) {
return value.toUpperCase()
}
})
npm i @types/js-cookie
Check out the Servers Docs
Check out the Contributing Guidelines
For vulnerability reports, send an e-mail to js-cookie at googlegroups dot com
Releasing should be done via the Release GitHub Actions workflow, so that published packages on npmjs.com have package provenance.
GitHub releases are created as a draft and need to be published manually! (This is so we are able to craft suitable release notes before publishing.)
Many thanks to BrowserStack for providing unlimited browser testing free of cost.