Skip to content
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions docs/start/framework/react/guide/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -758,3 +758,81 @@ Middleware functionality is tree-shaken based on the environment for each bundle

- On the server, nothing is tree-shaken, so all code used in middleware will be included in the server bundle.
- On the client, all server-specific code is removed from the client bundle. This means any code used in the `server` method is always removed from the client bundle. `data` validation code will also be removed.

## Middleware Factories

Static middlewares are created once and reused across routes. A middleware factory wraps that creation in a function, allowing it to accept parameters and behave differently depending on the caller's needs. Authorization is a common use case.

**Authentication (Static Base Middleware) Example:**

This middleware validates the session and injects it into `context` for downstream middlewares.

```tsx
// middleware.ts
import { createMiddleware } from '@tanstack/react-start'
import { auth } from './my-auth'

export const authMiddleware = createMiddleware().server(
async ({ next, request }) => {
const session = await auth.getSession({ headers: request.headers })

if (!session) {
throw new Error('Unauthorized')
}

return await next({
context: { session },
})
},
)
```

**Authorization (Middleware Factory) Example:**

The middleware validates access based on the dynamic `permissions` parameter, composing with `authMiddleware` so `context.session` is already available.

```tsx
// middleware.ts
import { createMiddleware } from '@tanstack/react-start'
import { auth } from './my-auth'

export const authMiddleware = createMiddleware()
.server(async ({ next, request }) => {
// ... (implementation from authentication example above)
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove the redundant authMiddleware declaration.

The authMiddleware is already fully defined in the authentication example above (lines 775-787). Redeclaring it here with an abbreviated comment creates unnecessary redundancy and may confuse readers.

📝 Suggested improvement

Option 1 (recommended): Remove the redundant declaration entirely since readers can reference the earlier complete example:

-export const authMiddleware = createMiddleware()
-  .server(async ({ next, request }) => {
-    // ... (implementation from authentication example above)
-  })
-
 type Permissions = Record<string, string[]>

Option 2: If showing the full structure is intentional for a self-contained example, add a comment clarifying this is a reference:

+// Using authMiddleware from the authentication example above
 export const authMiddleware = createMiddleware()
   .server(async ({ next, request }) => {
-    // ... (implementation from authentication example above)
+    const session = await auth.getSession({ headers: request.headers })
+    if (!session) {
+      throw new Error('Unauthorized')
+    }
+    return await next({
+      context: { session },
+    })
   })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const authMiddleware = createMiddleware()
.server(async ({ next, request }) => {
// ... (implementation from authentication example above)
})
Suggested change
export const authMiddleware = createMiddleware()
.server(async ({ next, request }) => {
// ... (implementation from authentication example above)
})
// Using authMiddleware from the authentication example above
export const authMiddleware = createMiddleware()
.server(async ({ next, request }) => {
const session = await auth.getSession({ headers: request.headers })
if (!session) {
throw new Error('Unauthorized')
}
return await next({
context: { session },
})
})
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/start/framework/react/guide/middleware.md` around lines 799 - 802,
Remove the redundant authMiddleware declaration block (the createMiddleware()...
.server async ({ next, request }) stub) since authMiddleware is already fully
defined earlier; locate the authMiddleware symbol and delete this abbreviated
redeclaration, or if you intend it as a self-contained reference instead of
deletion, replace the stub with a clear comment stating "Reference only — full
implementation shown above" so readers aren’t confused.


type Permissions = Record<string, string[]>

export function authorizationMiddleware(permissions: Permissions) {
return createMiddleware({ type: 'function' })
.middleware([authMiddleware])
.server(async ({ next, context }) => {
const granted = await auth.hasPermission(context.session, permissions)

if (!granted) {
throw new Error('Forbidden')
}

return await next()
})
}
```

**Usage in a Server Function:**

Access requirements are defined per server function, without duplicating any middleware logic.

```tsx
import { createServerFn } from '@tanstack/react-start'
import { authorizationMiddleware } from './middleware'

export const getClients = createServerFn()
.middleware([
authorizationMiddleware({
client: ['read'],
}),
])
.handler(async ({ context }) => {
return { message: 'The user can read clients.' }
})
```
Loading