Skip to content

session-middleware Overview

The remix/session-middleware package provides middleware that connects sessions to your router. It reads the session from the incoming request's cookie, makes it available to your handlers, and saves any changes back to the response automatically. You never need to manually parse cookies or call a save method.

Key Concepts

  • Middleware -- Code that runs before and after your route handlers. The session middleware runs on every request.
  • Session cookie -- The HTTP cookie that carries the session identifier (or the session data itself, when using cookie storage).
  • Session storage -- The backend that persists session data. The middleware uses the storage's read and save methods.
  • Auto-save -- The middleware saves the session after the handler returns, so you just call session.set() and the rest happens automatically.

How It Works

The session middleware performs five steps on every request:

Request
  1. Parse the session cookie from the Cookie header
  2. Load session data from storage (storage.read)
  3. Set context.get(Session) for downstream handlers
  4. Wait for the handler to return a response
  5. Save session changes to storage (storage.save)
  6. Add Set-Cookie header to the response
Response

You only interact with step 3 -- reading and writing session data in your handlers. Everything else is automatic.

Quick Example

ts
// app/session.ts
import { createCookie } from 'remix/cookie'
import { createCookieSessionStorage } from 'remix/session/cookie-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,
})

export let sessionStorage = createCookieSessionStorage(sessionCookie)
ts
// 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.get(homeRoute, async ({ context }) => {
  let s = context.get(Session)
  let visits = (s.get('visits') ?? 0) + 1
  s.set('visits', visits)
  return new Response(`You have visited ${visits} time(s).`)
})

Middleware Ordering

The session middleware must come before any middleware or handler that accesses the session. A typical stack:

ts
let router = createRouter({
  middleware: [
    formData(),                              // 1. Parse form data
    session(sessionCookie, sessionStorage),   // 2. Load session
    auth({ schemes: [sessionScheme] }),       // 3. Auth reads from session
  ],
})

If auth runs before session, the session will not be loaded yet and the auth scheme will not find a user.

What Gets Saved Automatically

The middleware saves after every request. This includes:

  • Values written with session.set(key, value)
  • Keys removed with session.unset(key)
  • Flash values consumed by session.get(key)
  • New session IDs from session.regenerateId()
  • Session destruction from session.destroy() (clears data and removes the cookie)

If nothing changed during the request, the middleware skips the save for efficiency but still refreshes the cookie's maxAge.

How It Fits Together

Next Steps

Released under the MIT License.