Files
bknd/docs/content/docs/(documentation)/usage/setup.mdx
T
2026-02-07 16:58:49 -06:00

181 lines
5.9 KiB
Plaintext

---
title: "Setup & Modes"
description: "Choose a mode and get bknd running with your app"
icon: Pin
tags: ["documentation"]
---
import { SquareMousePointer, Code, Blend } from 'lucide-react';
bknd supports three modes. Each mode determines how your backend is configured and where that configuration lives.
## Choose your mode
<Cards className="grid-cols-1 sm:grid-cols-2 md:grid-cols-3">
<Card title="UI-only (default)" href="#ui-only-mode" icon={<SquareMousePointer className="text-fd-primary !size-6" />}>
Configure visually via the Admin UI. Config is stored in the database.
</Card>
<Card title="Code-only" href="#code-only-mode" icon={<Code className="text-fd-primary !size-6" />}>
Define your schema in code with a Drizzle-like API. Config lives in your codebase.
</Card>
<Card title="Hybrid" href="#hybrid-mode" icon={<Blend className="text-fd-primary !size-6" />}>
Use the Admin UI in development, export to code for production.
</Card>
</Cards>
**Not sure which to pick?**
- **UI-only** is best for prototyping and small projects. No code needed — configure everything through the dashboard.
- **Code-only** is best for teams, CI/CD, and version-controlled schemas. You define your data structure programmatically.
- **Hybrid** gives you the best of both — visual configuration while developing, locked-down code config in production.
You can always change modes later. Start with UI-only if you're exploring.
---
## UI-only mode
This is the default. Run bknd and configure everything through the Admin UI. No setup code required beyond a database connection.
```typescript title="bknd.config.ts"
import type { BkndConfig } from "bknd";
export default {
connection: { url: "file:data.db" },
} satisfies BkndConfig;
```
If you want to provide an initial data structure (entities, auth settings, etc.), pass it via `config`. It will only be applied when the database is empty.
```typescript title="bknd.config.ts"
import type { BkndConfig } from "bknd";
export default {
connection: { url: "file:data.db" },
config: {
auth: { enabled: true },
},
} satisfies BkndConfig;
```
<Callout type="info">
In UI-only mode, the `config` property is only applied on first boot. After that, all changes are made through the Admin UI.
</Callout>
**Next step:** Pick your [framework or runtime integration](/integration/introduction) to wire bknd into your app.
---
## Code-only mode
Define your data structure programmatically with a Drizzle-like API. The Admin UI becomes read-only for configuration — you still use it to manage data.
```typescript title="bknd.config.ts"
import { type BkndConfig, em, entity, text, boolean } from "bknd";
import { secureRandomString } from "bknd/utils";
const schema = em({
todos: entity("todos", {
title: text(),
done: boolean(),
}),
});
export default {
connection: { url: "file:data.db" },
config: {
data: schema.toJSON(),
auth: {
enabled: true,
jwt: { secret: secureRandomString(64) },
},
},
options: {
mode: "code",
},
} satisfies BkndConfig;
```
Unlike UI-only mode, the `config` is applied on every boot. If you change the schema, you may need to [sync the database](/usage/cli#syncing-the-database-sync).
**Next step:** Pick your [framework or runtime integration](/integration/introduction) to wire bknd into your app.
---
## Hybrid mode
Use the Admin UI to configure your backend while developing. When you're ready to deploy, export the config and run in code mode for production.
```typescript title="bknd.config.ts"
import type { BkndConfig } from "bknd";
import appConfig from "./appconfig.json" with { type: "json" };
export default {
connection: { url: "file:data.db" },
config: appConfig,
options: {
mode: process.env.NODE_ENV === "development" ? "db" : "code",
manager: {
secrets: process.env,
},
},
} satisfies BkndConfig;
```
To export your config, secrets, and types, use the CLI or plugins:
| What | CLI Command | Plugin |
|------|-------------|--------|
| Configuration | [`bknd config`](/usage/cli/#getting-the-configuration-config) | [`syncConfig`](/extending/plugins/#syncconfig) |
| Secrets | [`bknd secrets`](/usage/cli/#getting-the-secrets-secrets) | [`syncSecrets`](/extending/plugins/#syncsecrets) |
| Types | [`bknd types`](/usage/cli/#generating-types-types) | [`syncTypes`](/extending/plugins/#synctypes) |
**Next step:** Pick your [framework or runtime integration](/integration/introduction) to wire bknd into your app.
---
## Mode helpers
For code and hybrid modes, bknd provides helper functions that handle syncing, mode switching, and schema validation automatically.
```typescript title="bknd.config.ts (code mode with Bun)"
import { code } from "bknd/modes";
import { type BunBkndConfig, writer } from "bknd/adapter/bun";
export default code<BunBkndConfig>({
connection: { url: "file:data.db" },
writer,
isProduction: Bun.env.NODE_ENV === "production",
typesFilePath: "bknd-types.d.ts",
});
```
```typescript title="bknd.config.ts (hybrid mode with Bun)"
import { hybrid } from "bknd/modes";
import { type BunBkndConfig, writer, reader } from "bknd/adapter/bun";
export default hybrid<BunBkndConfig>({
connection: { url: "file:data.db" },
writer,
reader,
secrets: await Bun.file(".env.local").json(),
isProduction: Bun.env.NODE_ENV === "production",
typesFilePath: "bknd-types.d.ts",
configFilePath: "bknd-config.json",
});
```
Mode helpers give you:
- Built-in syncing of config, types, and secrets
- Automatic schema syncing in development
- Automatic mode switching (db → code) in production for hybrid
- Skipped config validation in production for faster boot
---
## Further reading
- [Framework & runtime integrations](/integration/introduction) — wire bknd into Next.js, Astro, Bun, Cloudflare, etc.
- [Database configuration](/usage/database) — choose and configure your SQL database
- [Configuration reference](/extending/config) — full `BkndConfig` API, plugins, events, and lifecycle hooks