Frameworks
Next.js
HostBase in a Next.js (App Router) app with server-side sessions.
The recommended approach for the App Router is the @supabase/ssr package, which keeps the session in cookies and works in Server Components, Route Handlers and Server Actions.
Install
npm install @supabase/supabase-js @supabase/ssr
Environment variables
# .env.local
NEXT_PUBLIC_SUPABASE_URL=https://abcdefghijklmnopqrst.host.ulewicz.space
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
You can keep the same variable names as with Supabase — migrating then only means swapping the values.
Browser client
// lib/supabase/client.ts
import { createBrowserClient } from "@supabase/ssr";
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}
Server client
// lib/supabase/server.ts
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
export async function createClient() {
const cookieStore = await cookies();
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll: () => cookieStore.getAll(),
setAll: (list) => {
try {
list.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
);
} catch {
// called from a Server Component — the proxy refreshes the session
}
},
},
}
);
}
Fetching data in a Server Component
// app/todos/page.tsx
import { createClient } from "@/lib/supabase/server";
export default async function TodosPage() {
const supabase = await createClient();
const { data: todos } = await supabase.from("todos").select("id, task, done");
return (
<ul>
{todos?.map((t) => <li key={t.id}>{t.task}</li>)}
</ul>
);
}
Refreshing the session
In Next.js 16 middleware is called proxy.ts. Create it in the project root (or src/) and call supabase.auth.getUser() in it to refresh the token on every request — exactly as in Supabase's official @supabase/ssr guide.