Skip to content

Middleware

Middleware in TSKit runs on server functions to handle authentication, authorization, and rate limiting. Each middleware validates a condition and adds data to the function’s context.

Server functions use the .middleware() method to attach middleware before the handler runs. Middleware modules can chain together, with each one building on the context from the previous.

export const myFunction = createServerFn({ method: 'POST' })
.middleware([authMiddleware])
.handler(async ({ context }) => {
// context.user is available because authMiddleware attached it
})

TSKit ships with six middleware modules that compose into a chain:

graph TD
  RL[createRateLimitMiddleware] --> A[authMiddleware]
  A --> O[orgMiddleware]
  A --> EV[emailVerifiedMiddleware]
  A --> AD[adminMiddleware]
  O --> S[subscribedMiddleware]

Each middleware depends on the one above it. subscribedMiddleware needs org context, so it chains orgMiddleware internally. You only need to reference the final middleware you need - it pulls in its dependencies automatically.

Validates the session and provides context.user. If no session exists, redirects to /login.

.middleware([authMiddleware])
// context.user available

Chains authMiddleware and fetches the user’s active organization. Provides context.organization.

.middleware([orgMiddleware])
// context.user and context.organization available

Chains authMiddleware and throws if the user’s email is not verified.

.middleware([emailVerifiedMiddleware])
// only runs if email is verified

Chains orgMiddleware and checks that the organization has an active or trialing subscription. Provides context.subscription.

.middleware([subscribedMiddleware])
// context.user, context.organization, and context.subscription available

Chains authMiddleware and a rate limiter. Redirects to /dashboard if the user’s role is not admin.

.middleware([adminMiddleware])
// only runs for admin users

A factory that creates a rate-limiting middleware for a specific rule. See the Rate Limiting guide for details.

const uploadRateLimit = createRateLimitMiddleware('upload')
.middleware([uploadRateLimit, authMiddleware])

To create your own middleware, use createMiddleware from TanStack Start. Chain an existing middleware if you need its context:

import { createMiddleware } from '@tanstack/react-start'
import { authMiddleware } from '#/middleware/auth'
export const myMiddleware = createMiddleware({ type: 'function' })
.middleware([authMiddleware])
.server(async ({ next, context }) => {
// context.user is available from authMiddleware
// Do your check
if (!someCondition(context.user)) {
throw new Error('Not allowed')
}
// Pass along with extra context
return next({
context: { myData: 'something' },
})
})
FilePurpose
middleware/auth.tsSession validation, provides user
middleware/org.tsActive organization, chains auth
middleware/email-verified.tsEmail verification check
middleware/subscribed.tsSubscription check, chains org
middleware/admin.tsAdmin role check
middleware/rate-limit.tsRate limit middleware factory