session Overview
The remix/session package provides server-side sessions -- key-value stores that persist data across multiple HTTP requests for a single user. Sessions are the standard way to remember things like who is logged in, what is in a shopping cart, or which notification to show next.
Key Concepts
- Session -- A server-side key-value store tied to a specific user via a cookie. Each user gets their own session. The session lives on the server (or in the cookie itself, depending on the storage backend), and the user's browser only holds a cookie that identifies which session is theirs.
- Session ID -- A unique, random string that identifies a session. It is stored in the cookie and used by the storage backend to look up the session data.
- Session storage -- The backend that persists session data between requests. Remix includes built-in storage backends for cookies, the filesystem, memory, Redis, and Memcache.
- Flash data -- A value that is available for exactly one read. After it is read, it disappears. Flash data is commonly used for success or error messages after a redirect.
The Session API
Once you have a session (via the session middleware), you interact with it through these methods:
| Method | Description |
|---|---|
session.get(key) | Read a value. Flash values are consumed on read. |
session.set(key, value) | Write a value. Must be JSON-serializable. |
session.has(key) | Check if a key exists. |
session.unset(key) | Remove a key. |
session.flash(key, value) | Set a one-time value (consumed on the next get). |
session.destroy() | Mark the session for deletion. |
session.regenerateId() | Generate a new session ID (keeps data). |
session.id | The current session ID (read-only). |
session.data | The raw data object (read-only). |
Quick Example
import { Session } from 'remix/session'
router.map(route, async ({ context }) => {
let session = context.get(Session)
// Read
let userId = session.get('userId')
// Write
session.set('lastVisit', Date.now())
// Flash (one-time message)
let message = session.get('message') // consumed on read
// Check existence
if (session.has('cart')) {
// ...
}
// Remove a key
session.unset('tempData')
return new Response('OK')
})Storage Backends
Remix provides several session storage backends. Each implements the same SessionStorage interface, so you can swap between them without changing your application code.
| Backend | Import | Best For |
|---|---|---|
| Cookie | remix/session/cookie-storage | Simple apps, small sessions (under 4KB) |
| Filesystem | remix/session/fs-storage | Development, single-server deployments |
| Memory | remix/session/memory-storage | Testing and development only |
| Redis | remix/session-storage-redis | Production, multi-server deployments |
| Memcache | remix/session-storage-memcache | Production, multi-server deployments |
Cookie Storage
Stores session data directly in the cookie (encrypted and signed). No server-side storage needed, but limited to about 4KB.
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)Filesystem Storage
Stores each session as a JSON file on disk. Simple but does not work with multiple servers.
import { createFsSessionStorage } from 'remix/session/fs-storage'
let sessionStorage = createFsSessionStorage('./sessions')Memory Storage
Stores sessions in a Map in process memory. Data is lost when the process restarts. Use for testing only.
import { createMemorySessionStorage } from 'remix/session/memory-storage'
let sessionStorage = createMemorySessionStorage()Redis and Memcache
For production deployments with multiple servers, use Redis or Memcache. Sessions are stored centrally so any server can access any session.
import { createRedisSessionStorage } from 'remix/session-storage-redis'
let sessionStorage = createRedisSessionStorage({
url: process.env.REDIS_URL!,
ttl: 60 * 60 * 24 * 7,
})See the Redis storage overview and Memcache storage overview for details.
Flash Messages
Flash data is a common pattern for showing one-time messages after a redirect (the Post/Redirect/Get pattern). You set a flash value in one request, and it is available to read exactly once in the next request.
// In the form action (POST /books)
session.flash('notice', 'Book created successfully!')
return new Response(null, { status: 302, headers: { Location: '/books' } })
// In the next page load (GET /books)
let notice = session.get('notice') // "Book created successfully!"
// On the following request, notice is gone:
let notice = session.get('notice') // undefinedSession Security
Two important security practices when working with sessions:
- Regenerate the session ID after login. This prevents session fixation attacks, where an attacker sets a known session ID before the user logs in.
session.set('userId', user.id)
session.regenerateId()- Destroy the session on logout. This removes all session data and clears the cookie.
session.destroy()How It Fits Together
The remix/session package provides the Session class and storage backends. To actually load and save sessions on every request, you need:
- remix/session-middleware -- Reads the session on each request and saves changes to the response.
- remix/cookie -- Configures the cookie that carries the session ID.
Next Steps
- Tutorial: Sessions in Practice -- Store user preferences, implement flash messages, and switch storage backends.
- API Reference -- Complete documentation of every function, class, and type.