Skip to main content

session

A session management library for JavaScript. This package provides a flexible and secure way to manage user sessions in server-side applications with a flexible API for different session storage strategies.

Installation

npm i remix

Core API

Session

A session persists data for a specific user across multiple requests to a server.
import { createSession } from 'remix/session'

let session = createSession()
session.set('userId', '123')
session.set('count', 1)

let userId = session.get('userId') // '123'
let count = session.get('count') // 1

Properties

id
string
The unique identifier for this session
data
SessionData
The raw session data in a format suitable for storage. Note: Do not use this for normal reading of session data. Use the get method instead.
dirty
boolean
Whether this session has been modified since it was created
destroyed
boolean
Whether this session has been destroyed
deleteId
string | undefined
The session ID that will be deleted when the session is saved. This is set to the original session ID when the session ID is regenerated with the deleteOldSession option.
size
number
The number of key/value pairs in the session

Methods

get
Get a value from the session.
let userId = session.get('userId')
key
string
required
The key of the value to get
return
any
The value for the given key, or undefined if the key doesn’t exist
set
Set a value in the session.
session.set('userId', '123')
session.set('preferences', { theme: 'dark' })
key
string
required
The key of the value to set
value
any
required
The value to set. Pass null or undefined to remove the key.
has
Check if a value is stored for the given key.
if (session.has('userId')) {
  console.log('User is logged in')
}
key
string
required
The key to check
return
boolean
true if a value is stored for the given key, false otherwise
unset
Remove a value from the session.
session.unset('userId')
key
string
required
The key of the value to remove
flash
Set a value in the session that will be available only during the next request.
session.flash('message', 'User created successfully!')
session.flash('error', 'Invalid credentials')
key
string
required
The key of the value to flash
value
any
required
The value to flash
regenerateId
Regenerate the session ID while preserving the session data. This should be called after login or other privilege changes to prevent session fixation attacks.
// After successful login
session.set('userId', user.id)
session.regenerateId(true) // Delete old session
deleteOldSession
boolean
default:"false"
Whether to delete the old session data when the session is saved
destroy
Mark this session as destroyed. This prevents all further modifications to the session.
// On logout
session.destroy()

createSession

Create a new session.
import { createSession } from 'remix/session'

let session = createSession()
let sessionWithId = createSession('custom-id')
let sessionWithData = createSession('id', [{ userId: '123' }, { message: 'Welcome!' }])
id
string
The ID of the session. If not provided, a new cryptographically secure session ID will be generated.
initialData
SessionData
The initial data for the session in the format [valueData, flashData]
return
Session
The new session

createSessionId

Create a new cryptographically secure session ID.
import { createSessionId } from 'remix/session'

let id = createSessionId() // e.g., "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
return
string
A new session ID (UUID v4)

Storage Strategies

SessionStorage

An interface for storing and retrieving session data.
interface SessionStorage {
  read(cookie: string | null): Promise<Session>
  save(session: Session): Promise<string | null>
}
read
(cookie: string | null) => Promise<Session>
Retrieve a new session from storage based on the session cookie
save
(session: Session) => Promise<string | null>
Save session data in storage and return the session cookie. Returns null if no session cookie should be set.

createCookieSessionStorage

Creates a session storage that stores all session data in the session cookie itself.
import { createCookieSessionStorage } from 'remix/session/cookie-storage'

let storage = createCookieSessionStorage()

let session = await storage.read(cookieValue)
session.set('count', 1)
let cookie = await storage.save(session)
Note: This is suitable for production. However, the total size of the session cookie is limited to the browser’s maximum cookie size, typically 4096 bytes.
return
SessionStorage
A session storage that stores data in cookies

createMemorySessionStorage

Creates a session storage that stores all session data in memory.
import { createMemorySessionStorage } from 'remix/session/memory-storage'

let storage = createMemorySessionStorage()

let session = await storage.read(cookieValue)
session.set('count', 1)
let cookie = await storage.save(session)
Note: This is useful for testing and development. All session data is lost when the server restarts.
options
MemorySessionStorageOptions
Optional configuration
return
SessionStorage
A session storage that stores data in memory

createFsSessionStorage

Creates a session storage that stores session data in the filesystem.
import { createFsSessionStorage } from 'remix/session/fs-storage'

let storage = createFsSessionStorage('/tmp/sessions')

let session = await storage.read(cookieValue)
session.set('count', 1)
let cookie = await storage.save(session)
Note: This is a good choice for production environments. It requires access to a persistent filesystem.
directory
string
required
The directory where session files will be stored
return
SessionStorage
A session storage that stores data in the filesystem

Examples

Basic Session Management

import { createCookieSessionStorage } from 'remix/session/cookie-storage'

let storage = createCookieSessionStorage()

async function handleRequest(cookie: string | null) {
  let session = await storage.read(cookie)
  session.set('count', Number(session.get('count') ?? 0) + 1)
  return {
    session,
    cookie: await storage.save(session),
  }
}

let response1 = await handleRequest(null)
console.log(response1.session.get('count')) // 1

let response2 = await handleRequest(response1.cookie)
console.log(response2.session.get('count')) // 2

Flash Messages

import { createMemorySessionStorage } from 'remix/session/memory-storage'

let storage = createMemorySessionStorage()

async function requestIndex(cookie: string | null) {
  let session = await storage.read(cookie)
  return { session, cookie: await storage.save(session) }
}

async function requestSubmit(cookie: string | null) {
  let session = await storage.read(cookie)
  session.flash('message', 'success!')
  return { session, cookie: await storage.save(session) }
}

// Flash data is undefined on the first request
let response1 = await requestIndex(null)
console.log(response1.session.get('message')) // undefined

// Flash data is undefined on the same request it is set
let response2 = await requestSubmit(response1.cookie)
console.log(response2.session.get('message')) // undefined

// Flash data is available on the next request
let response3 = await requestIndex(response2.cookie)
console.log(response3.session.get('message')) // 'success!'

// Flash data is not available on subsequent requests
let response4 = await requestIndex(response3.cookie)
console.log(response4.session.get('message')) // undefined

Session Security: Regenerating IDs

import { createFsSessionStorage } from 'remix/session/fs-storage'

let sessionStorage = createFsSessionStorage('/tmp/sessions')

async function requestLogin(cookie: string | null) {
  let session = await sessionStorage.read(cookie)
  
  // Verify credentials...
  
  session.set('userId', 'mj')
  // Regenerate session ID after privilege change
  session.regenerateId(true) // true = delete old session
  
  return { session, cookie: await sessionStorage.save(session) }
}

let response = await requestLogin(null)
console.log(response.session.get('userId')) // 'mj'

User Authentication Flow

import { createCookieSessionStorage } from 'remix/session/cookie-storage'

let storage = createCookieSessionStorage()

// Login handler
async function login(cookie: string | null, credentials: { username: string; password: string }) {
  let session = await storage.read(cookie)
  
  // Verify credentials
  let user = await verifyCredentials(credentials)
  
  if (!user) {
    session.flash('error', 'Invalid credentials')
    return { session, cookie: await storage.save(session) }
  }
  
  // Set user data and regenerate session ID for security
  session.set('userId', user.id)
  session.set('username', user.username)
  session.regenerateId(true)
  
  session.flash('message', 'Login successful!')
  return { session, cookie: await storage.save(session) }
}

// Logout handler
async function logout(cookie: string | null) {
  let session = await storage.read(cookie)
  session.destroy()
  return { cookie: await storage.save(session) }
}

// Protected route
async function getProfile(cookie: string | null) {
  let session = await storage.read(cookie)
  
  let userId = session.get('userId')
  if (!userId) {
    return { error: 'Unauthorized', status: 401 }
  }
  
  let user = await getUserById(userId)
  return { user, cookie: await storage.save(session) }
}

TypeScript: Typed Sessions

import { createSession, type Session } from 'remix/session'

interface UserData {
  userId: string
  username: string
  role: 'admin' | 'user'
}

interface FlashData {
  message: string
  error: string
}

let session = createSession<UserData, FlashData>()

// Type-safe access
session.set('userId', '123')
session.set('role', 'admin')
session.flash('message', 'Welcome!')

let userId: string | undefined = session.get('userId')
let role: 'admin' | 'user' | undefined = session.get('role')

Build docs developers (and LLMs) love