remix/session
The remix/session package provides the core session API for Remix V3. Sessions are server-side key-value stores associated with a user via a cookie. They are used to persist data across requests --- login state, flash messages, shopping carts, and more.
Installation
The remix/session package is included with Remix. No additional installation is required.
import { createSession, createSessionId, Session } from 'remix/session'createSession(data?)
Creates a new Session instance with optional initial data.
function createSession(data?: Record<string, unknown>): SessionParameters:
| Parameter | Type | Description |
|---|---|---|
data | Record<string, unknown> | Optional. Initial key-value pairs to populate the session with. |
Example:
import { createSession } from 'remix/session'
// Empty session
let session = createSession()
// Session with initial data
let session = createSession({
userId: 42,
theme: 'dark',
})createSessionId()
Generates a cryptographically random session ID string.
function createSessionId(): stringReturns a unique string suitable for use as a session identifier. You typically do not need to call this directly --- session storage backends generate IDs automatically. It is exposed for advanced use cases such as custom storage implementations.
Example:
import { createSessionId } from 'remix/session'
let id = createSessionId()
// e.g. "a1b2c3d4e5f6..."Session Context Key
The Session export serves double duty: it is both the session class and a context key. When used with context.get(Session), it retrieves the current request's session (set by the session middleware).
import { Session } from 'remix/session'
router.map(route, async ({ context }) => {
let session = context.get(Session)
let userId = session.get('userId')
})Session Class API
session.get(key)
Reads a value from the session.
session.get(key: string): unknownReturns the value associated with the key, or undefined if the key does not exist. Flash values are returned once and then automatically removed.
Example:
let userId = session.get('userId') // number | undefined
let theme = session.get('theme') // string | undefined
let flash = session.get('message') // string | undefined (consumed on read)session.set(key, value)
Writes a value to the session.
session.set(key: string, value: unknown): voidValues must be JSON-serializable: strings, numbers, booleans, arrays, plain objects, and null.
Example:
session.set('userId', 42)
session.set('theme', 'dark')
session.set('cart', [{ productId: 1, quantity: 2 }])session.has(key)
Checks whether a key exists in the session.
session.has(key: string): booleanReturns true if the key exists (including flash keys that have not yet been read), false otherwise.
Example:
if (session.has('userId')) {
// User is logged in
}session.unset(key)
Removes a single key from the session.
session.unset(key: string): voidExample:
session.unset('cart')
// session.get('cart') now returns undefinedsession.flash(key, value)
Sets a value that is available for one subsequent read only. After it is read with session.get(key), it is automatically removed.
session.flash(key: string, value: unknown): voidFlash values are ideal for success or error messages after a redirect (the Post/Redirect/Get pattern).
Example:
// In the action handler
session.flash('message', 'Book created successfully!')
return new Response(null, { status: 302, headers: { Location: '/books' } })
// In the next request's handler
let message = session.get('message') // "Book created successfully!"
// On the following request:
let message = session.get('message') // undefinedsession.destroy()
Marks the session for deletion. All data is cleared, and the session cookie will be removed from the response. The deletion is carried out by the session middleware when it saves the response.
session.destroy(): voidExample:
// Logout handler
session.destroy()
return new Response(null, { status: 302, headers: { Location: '/login' } })session.regenerateId(deleteOld?)
Generates a new session ID while preserving all session data. This is a security best practice after authentication state changes (login, privilege escalation) to prevent session fixation attacks.
session.regenerateId(deleteOld?: boolean): voidParameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
deleteOld | boolean | true | Whether to delete the old session from storage. Set to false to keep the old session (rare). |
Example:
// After a successful login
session.set('userId', user.id)
session.regenerateId()
// The session now has a new ID, but the same datasession.id
The current session ID. A read-only string property.
session.id: stringExample:
console.log(session.id) // "a1b2c3d4e5f6..."session.data
The raw session data object. A read-only property that returns the underlying key-value store. Prefer using get, set, has, and unset instead of accessing this directly.
session.data: Record<string, unknown>Example:
console.log(session.data) // { userId: 42, theme: 'dark' }SessionStorage Interface
Session storage backends implement the SessionStorage interface:
interface SessionStorage {
read(cookie: string): Promise<Session>
save(session: Session): Promise<string>
}| Method | Description |
|---|---|
read(cookie) | Parses the cookie value, retrieves session data from storage, and returns a Session instance. If the cookie is empty or the session does not exist, returns a new empty session. |
save(session) | Persists the session data to storage and returns the cookie value to set in the response. Handles creating new sessions, updating existing ones, and deleting destroyed sessions. |
You typically do not interact with SessionStorage directly. The session middleware calls read and save automatically.
Sub-Exports
remix/session/cookie-storage
Stores session data directly inside the cookie (encrypted and signed). No server-side storage is needed.
import { createCookieSessionStorage } from 'remix/session/cookie-storage'createCookieSessionStorage(cookie)
function createCookieSessionStorage(cookie: Cookie): SessionStorageParameters:
| Parameter | Type | Description |
|---|---|---|
cookie | Cookie | A cookie created with createCookie() from remix/cookie. The cookie's secrets are used to encrypt and sign the session data. |
Pros: No external dependencies, works everywhere, zero latency. Cons: Limited to approximately 4KB of data, session data is sent with every request.
Example:
import { createCookie } from 'remix/cookie'
import { createCookieSessionStorage } from 'remix/session/cookie-storage'
let sessionCookie = createCookie('__session', {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'Lax',
secrets: [process.env.SESSION_SECRET!],
maxAge: 60 * 60 * 24 * 7,
})
let sessionStorage = createCookieSessionStorage(sessionCookie)remix/session/fs-storage
Stores session data as files on the local filesystem.
import { createFsSessionStorage } from 'remix/session/fs-storage'createFsSessionStorage(directory)
function createFsSessionStorage(directory: string): SessionStorageParameters:
| Parameter | Type | Description |
|---|---|---|
directory | string | The directory path where session files are stored. Created automatically if it does not exist. |
Pros: Simple, no extra software needed. Cons: Does not work with multiple servers (each server has its own files). Not suitable for serverless or container deployments where the filesystem is ephemeral.
Example:
import { createFsSessionStorage } from 'remix/session/fs-storage'
let sessionStorage = createFsSessionStorage('./sessions')Each session is stored as a separate JSON file (e.g. ./sessions/a1b2c3d4e5f6.json).
remix/session/memory-storage
Stores session data in-process memory. Intended for testing and development only.
import { createMemorySessionStorage } from 'remix/session/memory-storage'createMemorySessionStorage()
function createMemorySessionStorage(): SessionStorageTakes no arguments. All session data is stored in a Map in memory.
Pros: Fast, no dependencies, no setup. Cons: Data is lost when the process restarts. Not suitable for production. Does not work with multiple servers.
Example:
import { createMemorySessionStorage } from 'remix/session/memory-storage'
let sessionStorage = createMemorySessionStorage()Complete Example
// app/session.ts
import { createCookie } from 'remix/cookie'
import { createFsSessionStorage } from 'remix/session/fs-storage'
export let sessionCookie = createCookie('__session', {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'Lax',
secrets: [process.env.SESSION_SECRET!],
maxAge: 60 * 60 * 24 * 7, // 1 week
})
export let sessionStorage = createFsSessionStorage('./sessions')// app/server.ts
import { createRouter } from 'remix/fetch-router'
import { session } from 'remix/session-middleware'
import { Session } from 'remix/session'
import { sessionCookie, sessionStorage } from './session.ts'
let router = createRouter({
middleware: [
session(sessionCookie, sessionStorage),
],
})
router.map(route, async ({ context }) => {
let s = context.get(Session)
// Read
let userId = s.get('userId')
// Write
s.set('lastVisit', Date.now())
// Flash (one-time read)
let message = s.get('message')
// Destroy (logout)
// s.destroy()
// Regenerate ID (after login)
// s.regenerateId()
})Related
- Sessions & Cookies -- Conceptual guide to sessions and cookies
- remix/session-middleware -- Middleware that integrates sessions with the router
- remix/cookie -- Cookie creation and configuration
- remix/session-storage-redis -- Redis session storage backend
- remix/session-storage-memcache -- Memcache session storage backend