Choose the right middleware scope, explain the execution chain, and avoid treating client-sent context as trusted authorization data.
Choose the scope first
Request middleware can cover SSR, Server Routes, and Server Functions. Middleware with type: 'function' wraps Server Functions and additionally supports client phases and data validation. Put a rule in the narrowest scope that still covers the requirement.
The chain advances only through next
Middleware can run before next(), add context for downstream code, and inspect the result after next() returns. Intentionally omitting next() short-circuits the chain; accidentally omitting it prevents the downstream handler from running.
import { createMiddleware } from '@tanstack/react-start'
export const timingMiddleware = createMiddleware({ type: 'function' })
.server(async ({ next }) => {
const startedAt = performance.now()
const result = await next()
console.info('server function ms', performance.now() - startedAt)
return result
})Turn this lesson into a verifiable skill
Request and function middleware have explicit scopes, and context flows in declared order.
Compose request-id and function-timing middleware, then read the id in a handler and emit structured logs.
Send two concurrent requests; each should have an independent id and timing should cover the full handler chain.
- Forgetting to return or await next().
- Storing request data in module-level mutable state.