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.
Before you start, create an FFDB app in the dashboard and copy your app URL and admin token.
Why this flow is ordered this way
- Generate types first so every query in your app is type-safe from day one.
- Initialize the client once so auth/query/sync all share one runtime state.
- Authenticate before user-scoped queries to avoid invalid startup reads.
- 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
Keep admin credentials out of browser code. Use them for local tooling and trusted server-side workflows.
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()
In provider-based React setups, the provider manages lifecycle. In scripts and service code, call destroy() explicitly.
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
- Create an app for the full scaffold flow.
- Generate types for options and output behavior.
- Client for the complete client API surface.