Next.js

For Next.js App Router apps, the standard FFDB pattern is a client-side provider wrapper at the root plus session-aware hooks inside client components.

  • Name
    Centralized client lifecycle
    Description

    One provider in the root layout keeps client creation and cleanup predictable.

  • Name
    Framework-aligned rendering
    Description

    Hooks run in client components where auth/session and browser state are available.

  • Name
    Template parity
    Description

    Matches the FFDB Next.js overlay generated by ffdb-cli init.

Environment setup

Add your FFDB app URL to .env.local:

NEXT_PUBLIC_FFDB_API_URL="https://your-app.ffdb.forever-frameworks.com"

Provider component

Create providers.tsx as a client component:

'use client'

import { FFDBProvider } from 'ffdb-client/react'
import type { Database } from '@/types/ffdb.types'

export function AppProviders({ children }: { children: React.ReactNode }) {
  return (
    <FFDBProvider<Database>
      options={{
        config: {
          apiUrl: process.env.NEXT_PUBLIC_FFDB_API_URL,
        },
      }}
    >
      {children}
    </FFDBProvider>
  )
}

Root layout wiring

Wrap your app tree in the provider from layout:

import { AppProviders } from '@/providers'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <AppProviders>{children}</AppProviders>
      </body>
    </html>
  )
}

End-to-end page flow

Use auth + query hooks in client pages or components:

'use client'

import { useAuth, useFFDB, useQuery } from 'ffdb-client/react'

export default function DashboardPage() {
  const ffdb = useFFDB()
  const auth = useAuth()
  const session = auth.useSession()

  const { data, isLoading } = useQuery(
    (db) =>
      db
        .selectFrom('user')
        .select(['id', 'email'])
        .where('id', '=', session.data?.user?.id ?? ''),
    {
      enabled: Boolean(session.data?.user?.id),
      deps: [session.data?.user?.id],
    },
  )

  if (ffdb.isLoading || session.isPending) return <p>Loading...</p>

  return isLoading ? <p>Fetching user...</p> : <pre>{JSON.stringify(data, null, 2)}</pre>
}

Practical guidance

  1. Keep provider and data hooks in client components.
  2. Use session.data?.user?.id driven enabled flags to avoid premature queries.
  3. Prefer typed query-builder calls for most reads and writes.
  4. Add sync status UI if offline mode is enabled.

Next pages

  1. Expo
  2. Node.js
  3. Electron

Was this page helpful?