> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firstflow.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Next.js

> Use @firstflow/runtime in a Next.js app: mount the provider in a client component and keep the service-role key on the server.

`@firstflow/runtime` works in any React setup. In Next.js (App Router) the only rules are the usual ones: the provider is a client component, and your server-only Supabase key never crosses into the browser.

## Provider in a client component

The provider uses hooks and `localStorage`, so it must run on the client. Wrap it in a `"use client"` component and mount that in your layout.

```tsx app/firstflow-provider.tsx theme={null}
"use client";

import "@firstflow/runtime/styles.css";
import { FirstflowProvider, FirstflowWidget } from "@firstflow/runtime";
import { createSupabasePersistence } from "@firstflow/runtime/supabase";
import { createClient } from "@supabase/supabase-js";
import experiences from "@/firstflow/experiences.json";

const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
);

export function Firstflow({ children }: { children: React.ReactNode }) {
  return (
    <FirstflowProvider
      experiences={experiences}
      persistence={createSupabasePersistence(supabase)}
    >
      {children}
      <FirstflowWidget />
    </FirstflowProvider>
  );
}
```

```tsx app/layout.tsx theme={null}
import { Firstflow } from "./firstflow-provider";

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <Firstflow>{children}</Firstflow>
      </body>
    </html>
  );
}
```

## Environment variables

Only the browser-safe pair carries the `NEXT_PUBLIC_` prefix. The server SDK's `service_role` key must not:

```bash theme={null}
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
SUPABASE_SERVICE_ROLE_KEY=eyJ...   # server-only use in route handlers, never in client components
```

## Wrapping LLM calls in route handlers

Use the [server SDK](/server/overview) inside route handlers (or server actions), where the `service_role` key is safe:

```ts app/api/chat/route.ts theme={null}
import { Firstflow } from "@firstflow/runtime-server";
import { createSupabaseLLMPersistence } from "@firstflow/runtime-server/supabase";
// build the service-role Supabase client here, server-side only
```

## Notes

* The browser runtime has no conversation id. Link the two sides by passing the same `user.id` to the provider and to your server calls; the server-side `conversationId`/`sessionId` is owned by your own chat code.
* Identify users from your auth in the client component (`user={...}`); omit it for anonymous visitors.
