Middleware
Run fast request-aware checks before route loading and keep authentication data scoped to the active request.
Use middleware to control route flow
Middleware runs before loaders and rendering. It can allow navigation or redirect to another same-origin path with an optional redirect status. Use it for fast routing decisions rather than slow page data.
Use page middleware when the check belongs to one route.
Use layout middleware when descendants share the check.
Register plugin middleware for application-wide integration behavior.
Prefer hosting or platform redirect rules for unconditional redirects that do not need application request data.
Keep session checks on the server
defineServerMiddleware prevents the check from running during browser navigation. It is the right boundary for HttpOnly cookies, server sessions, private clients, and permission prechecks.
Because it is skipped during SPA navigation, server-only middleware is not a client navigation gate. Pair it with safe hydrated auth state or client navigation handling, and keep the real authorization check in every protected loader, action, and server route.
Create src/pages/account.tsx
tsximport { defineServerMiddleware } from "@tavojs/core/router";
import { Page, Text } from "@tavojs/ui";
export const middleware = defineServerMiddleware(async ({ request }) => {
const { readSession } = await import("./session.server");
const session = await readSession(request);
if (!session) return { redirect: "/login" };
});
export default function AccountPage() {
return (
<Page>
<Text>Account</Text>
</Page>
);
}
Know which middleware guards each entry path
| Entry path | Page middleware | Server-only middleware | Final authorization |
|---|---|---|---|
| Direct SSR request | Runs | Runs | Repeat in loader or action |
| Hydration | Uses resolved route state | Does not rerun | Use only safe serialized identity |
| Later SPA navigation | Runs | Skipped | Protected loader or endpoint decides |
| Direct action or API request | Not a security boundary | Depends on registered request pipeline | Action or handler must enforce it |
Keep request data request-scoped
Read headers, cookies, and the URL from the supplied context. Pass only safe derived values through loader results or server services designed for the active request. Do not write the current user into a global store or module variable.
Keep middleware fast and abortable
Middleware receives the navigation AbortSignal. Pass it to downstream work and stop promptly when navigation changes. Move route-critical data into a loader and avoid remote calls in middleware when a local cookie or claim is enough for the routing decision.