Quickstart

This guide takes you from zero to a working FFDB app connection: install tooling, generate schema types, initialize the client, sign in, and query data.

Why this flow is ordered this way

  1. Generate types first so every query in your app is type-safe from day one.
  2. Initialize the client once so auth/query/sync all share one runtime state.
  3. Authenticate before user-scoped queries to avoid invalid startup reads.
  4. Validate with one real query before building larger features.

1. Install dependencies

Install the FFDB client in your app:

npm install ffdb-client

Install the FFDB CLI if you want type generation and scaffolding commands available globally:

npm install -g ffdb-cli

2. Choose a setup path

If you are starting a new app, scaffold it with the CLI:

ffdb-cli init

If you already have an app, continue with manual setup below.

3. Generate TypeScript types

Generate a typed Database interface from your FFDB app:

ffdb-cli generate \
  --url https://your-app.ffdb.forever-frameworks.com \
  --token your-admin-token \
  --out ./src/ffdb.types.ts

You can also put values in .env and run without inline credentials:

API_URL="https://your-app.ffdb.forever-frameworks.com"
FFDB_AUTH_TOKEN="your-admin-token"
ffdb-cli generate --out ./src/ffdb.types.ts

4. Create the client

Create an FFDB client with your generated Database type:

import { createClient } from 'ffdb-client'
import type { Database } from './ffdb.types'

const { db, auth, destroy } = await createClient<Database>({
  config: {
    apiUrl: import.meta.env.VITE_FFDB_API_URL,
  },
})

You can think of this result as three layers:

  • Name
    db
    Description

    Type-safe query builder surface for your generated schema.

  • Name
    auth
    Description

    User session and sign-in/sign-out methods.

  • Name
    destroy
    Description

    Cleanup hook for scripts, services, and controlled app shutdown.

5. Authenticate a user

Sign in and verify session availability:

await auth.signIn.email({
  email: '[email protected]',
  password: 'password',
})

const { data: session } = await auth.getSession()
console.log(session?.user)

6. Run your first query

Use the typed query builder:

const users = await db
  .selectFrom('user')
  .select(['id', 'email'])
  .execute()

console.log(users)

Why this query matters: it confirms your generated types, runtime URL config, session context, and query execution path all line up.

7. React setup (optional)

Use FFDBProvider for app-level wiring and hooks for data access:

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

function Root() {
  return (
    <FFDBProvider<Database>
      options={{
        config: {
          apiUrl: import.meta.env.VITE_FFDB_API_URL,
        },
      }}
    >
      <Users />
    </FFDBProvider>
  )
}

function Users() {
  const { data } = useQuery((db) => db.selectFrom('user').selectAll().execute())
  return <pre>{JSON.stringify(data, null, 2)}</pre>
}

8. Cleanup

If you created the client manually, clean it up when shutting down:

await destroy()

Common first-run issues

  • Name
    Type generation fails
    Description

    Re-check API URL and admin token values before troubleshooting app code.

  • Name
    Session is null after sign-in
    Description

    Call auth.getSession() again and ensure your app uses one shared client instance.

  • Name
    Query returns empty results
    Description

    Confirm table names and seeded rows in your FFDB app.

Next steps

  1. Create an app for the full scaffold flow.
  2. Generate types for options and output behavior.
  3. Client for the complete client API surface.

Was this page helpful?