getting-started
Getting Started with Bknd
Bknd is a lightweight, embeddable backend framework that provides an instant REST API, authentication, database management, and admin UI. It integrates directly into your application or runs standalone.
What You'll Learn
- Create a new Bknd project with popular frameworks
- Configure your database and schema
- Start the development server
- Access the Admin UI
- Choose the right configuration mode
Quick Start
The fastest way to explore Bknd:
npx bknd run
This starts a temporary instance with:
- In-memory SQLite database
- Admin UI at
http://localhost:3000 - REST API at
http://localhost:3000/api
Note: This is for exploration only. For a real project, follow the steps below.
Project Setup
Step 1: Create a Framework Project
Bknd works with any JavaScript framework. Here are common starting points:
Vite + React:
npx bknd create my-bknd-app --integration vite --template react
cd my-bknd-app
Next.js:
npx create-next-app@latest my-bknd-app
cd my-bknd-app
npm install bknd
Bun (Standalone):
npx bknd create my-bknd-app --integration bun
cd my-bknd-app
Step 2: Create Configuration File
Create bknd.config.ts in your project root:
import { createApp, em, entity, text, boolean } from "bknd";
import type { ViteBkndConfig } from "bknd/adapter/vite";
// Define your data model (Code Mode)
const schema = em({
todos: entity("todos", {
title: text().required(),
done: boolean(),
}),
});
export default {
connection: {
url: "file:data.db",
},
config: {
data: schema.toJSON(),
},
} satisfies ViteBkndConfig;
This configures:
- Database: SQLite stored in
data.db - Schema: A
todosentity withtitle(text) anddone(boolean) fields - Auto-generated: Bknd automatically adds an
idfield (string/uuid)
Step 3: Start the Development Server
Vite + React:
Create server.ts:
import { serve } from "bknd/adapter/vite";
import config from "./bknd.config";
export default serve(config);
Update vite.config.ts:
import { devServer } from "bknd/adapter/vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [
react(),
devServer({
entry: "./server.ts",
}),
],
});
Start the server:
npm run dev
Next.js:
Create app/api/[[...bknd]]/route.ts:
import { serve } from "bknd/adapter/nextjs";
import config from "@/bknd.config";
export const runtime = "nodejs";
const { handler } = serve(config);
export { handler as GET, handler as POST, handler as PUT, handler as DELETE };
Start the server:
npm run dev
Bun (Standalone):
Create server.ts:
import { serve } from "bknd/adapter/bun";
import config from "./bknd.config";
export default {
port: 3000,
fetch: serve(config),
};
Start the server:
bun run server.ts
Step 4: Verify Setup
Visit http://localhost:3000/api/system/config to confirm the API is running. You should see JSON configuration output.
Accessing the Admin UI
The Admin UI provides a visual interface for managing your data and configuration.
Mounting the Admin UI:
Vite + React (replace App.tsx):
import { Admin } from "bknd/ui";
import "bknd/dist/styles.css";
export default function App() {
return <Admin withProvider />;
}
Next.js (create app/admin/page.tsx):
"use client";
import { Admin } from "bknd/ui";
import "bknd/dist/styles.css";
export default function AdminPage() {
return <Admin />;
}
Bun (requires separate frontend):
Use the Admin UI by creating a separate React app or integrating with an existing one.
Access the Admin UI at http://localhost:3000/ (or http://localhost:3000/admin for Next.js).
Configuration Modes
Bknd supports three configuration modes. Choose based on your workflow:
| Mode | Schema Definition | Type Generation | Performance | Best For |
|---|---|---|---|---|
| Code Mode | TypeScript code | Static, generated once | Fastest | Production, version-controlled schemas |
| Hybrid Mode | Code + Admin UI | Synced on changes | Balanced | Development with UI flexibility |
| UI Mode | Admin UI only | Dynamic (per request) | Slowest | Prototyping, non-technical users |
Code Mode (Recommended for Production)
Schema is defined in bknd.config.ts:
const schema = em({
todos: entity("todos", {
title: text().required(),
done: boolean(),
}),
});
export default {
config: {
data: schema.toJSON(),
},
} satisfies BkndConfig;
Benefits:
- Version-controlled schema
- Type-safe code
- Fastest performance (no database lookups)
- Ideal for CI/CD
UI Mode
Remove the config.data object from your config:
export default {
connection: {
url: "file:data.db",
},
} satisfies BkndConfig;
Define entities through the Admin UI at http://localhost:3000/.
Benefits:
- Visual schema creation
- No code changes for schema updates
- Ideal for prototyping
Trade-offs:
- Slower performance (database reads per request)
- Not version-controlled
- Requires separate type generation step
Hybrid Mode
Use both code and UI. Set sync_required in config:
const schema = em({
todos: entity("todos", {
title: text().required(),
done: boolean(),
}),
});
export default {
config: {
data: schema.toJSON(),
sync_required: true,
},
} satisfies BkndConfig;
Benefits:
- Code defines baseline schema
- UI overrides allowed in development
- Production uses code (enforced sync)
Workflow:
- Define schema in code
- Make changes in Admin UI (development only)
- Sync changes back to code with
npx bknd sync
Common CLI Commands
# Start interactive mode
npx bknd run
# Generate TypeScript types from schema
npx bknd types
# Sync UI mode changes to code (Hybrid mode)
npx bknd sync
# Start MCP server for AI integration
npx bknd mcp
Database Options
Bknd supports multiple database backends:
SQLite (Default):
import { nodeSqlite } from "bknd/adapter/node";
export default {
connection: nodeSqlite({
url: "file:data.db",
}),
} satisfies NodeBkndConfig;
PostgreSQL:
import { pg } from "bknd";
export default {
connection: pg({
url: "postgres://user:pass@host:5432/dbname",
}),
} satisfies BkndConfig;
Cloudflare D1:
import { d1 } from "bknd/adapter/cloudflare";
export default {
connection: d1({
binding: "DB", // From wrangler.toml
}),
} satisfies D1BkndConfig;
Architecture Overview
┌─────────────────────────────────────────────────────────────┐
│ Your Application │
│ (Next.js / Astro / Remix) │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Bknd │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Auth │ │ Data │ │ Media │ │ Flows │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ REST API (Hono) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Admin UI (React) │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────┬───────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Database │
│ (SQLite / PostgreSQL / D1 / Turso) │
└─────────────────────────────────────────────────────────────┘
Next Steps
- Data Schema - Define entities, field types, and relationships
- Query - Learn the query system (where, sort, with)
- Auth - Implement authentication strategies
- Permissions - Configure access control
DOs and DON'Ts
DO:
- Use Code Mode for production applications
- Generate types with
npx bknd typesfor type safety - Start with
npx bknd runto explore the Admin UI - Use SQLite for development, switch to PostgreSQL for production
DON'T:
- Deploy with UI Mode in production (slow performance)
- Skip type generation (you lose TypeScript benefits)
- Define the same entity twice in
em() - Commit
data.dbto version control
Common Issues
"Module not found" errors:
- Ensure you installed the adapter package (e.g.,
@hono/vite-dev-server) - Check your import paths match your adapter
Admin UI not loading:
- Verify you imported the CSS:
import "bknd/dist/styles.css" - Ensure the server is running on the correct port
Database locked errors (SQLite):
- Enable WAL mode for better concurrent access:
nodeSqlite({ url: "file:data.db", onCreateConnection: (db) => db.exec("PRAGMA journal_mode = WAL;"), })