permix
Version:
Permix is a lightweight, framework-agnostic, type-safe permissions management library for JavaScript applications on the client and server sides.
101 lines (73 loc) • 2.98 kB
Markdown
---
name: permix-ssr
description: >-
Serializes Permix permissions for SSR: dehydrate, hydrate, client setup,
PermixHydrate, Next.js and TanStack Start. Use when passing permissions from
server to client or permix.dehydrate in SSR apps.
type: sub-skill
library: permix
library_version: '4.1.1'
requires:
- permix-getting-started
- permix-frontend
sources:
- 'letstri/permix:docs/content/docs/guide/hydration.mdx'
- 'letstri/permix:docs/content/docs/integrations/next.mdx'
- 'letstri/permix:docs/content/docs/integrations/tanstack-start.mdx'
- 'letstri/permix:permix/src/next/index.ts'
- 'letstri/permix:permix/src/tanstack-start/index.ts'
---
# Permix — SSR and hydration
Docs: https://permix.letstri.dev/docs/guide/hydration
## Why dehydrate?
Send a JSON snapshot of booleans to the browser so the first paint can respect permissions without re-fetching policy on the client.
## Server
```ts
permix.setup(serverRules)
const state = permix.dehydrate()
// { post: { create: true, read: false } } — functions evaluated once without data
```
Pass `state` to the client (embed in HTML, RSC payload, loader data, etc.).
## Client
```ts
permix.hydrate(state)
// isReady() is still FALSE — hydrate only restores booleans
```
Function-based rules are **lost** in JSON (dehydration calls functions with no data; missing required data → `false`).
**Always call `setup` again on the client** with full rules (including closures):
```ts
permix.hydrate(serverState)
permix.setup(clientRulesForUser) // restores functions + sets ready
```
Skipping client `setup` after hydrate leaves dynamic/ReBAC checks wrong.
## React
```tsx
import { DehydratedState, PermixHydrate, PermixProvider } from 'permix/react'
function App({ dehydratedState }: { dehydratedState: DehydratedState<typeof schema> }) {
return (
<PermixProvider permix={permix}>
<PermixHydrate state={dehydratedState}>
<YourApp />
</PermixHydrate>
</PermixProvider>
)
}
```
Run client `permix.setup(...)` where you restore the session (e.g. after `PermixHydrate` mounts or in the same auth effect).
## Next.js / TanStack Start
Use framework helpers from `permix/next` or `permix/tanstack-start` when available — they wire dehydrate/hydrate into the framework data flow.
Docs:
- https://permix.letstri.dev/docs/integrations/next
- https://permix.letstri.dev/docs/integrations/tanstack-start
## Flow diagram
```text
Server: setup(rules) → dehydrate() → send state
Client: hydrate(state) → setup(fullRules) → isReady() → check() / usePermix
```
## Pitfalls
| Issue | Cause |
|-------|--------|
| UI stuck not ready | `hydrate` without follow-up `setup` |
| Wrong dynamic checks | Relying on dehydrated booleans only |
| Mismatch server/client | Different schemas or missing actions in client `setup` |
For static-only permissions (all booleans), dehydrate + hydrate + `setup` with the same booleans is enough; still call `setup` to mark ready.