Getting Started
Get started with Quickback in minutes. Learn how to define database tables with security configuration and compile them into a production-ready API.
Get started with Quickback in minutes. This guide shows you how to define a complete table with security configuration.
Install the CLI
npm install -g @kardoe/quickbackCreate a Project
quickback create cloudflare my-app
cd my-appThis scaffolds a complete project with:
quickback.config.ts— Project configurationdefinitions/features/— Your table definitions- Example todos feature with full security configuration
Available templates:
cloudflare— Cloudflare Workers + D1 + Better Auth (free)bun— Bun + SQLite + Better Auth (free)turso— Turso/LibSQL + Better Auth (pro)
File Structure
Each table gets its own file with schema and config together using defineTable:
definitions/
└── features/
└── rooms/
├── rooms.ts # Table + security config
├── room-bookings.ts # Related table + config
├── actions.ts # Custom actions (optional)
└── handlers/ # Action handlers (optional)
└── activate.tsComplete Example
Here's a complete rooms table with all security layers:
// definitions/features/rooms/rooms.ts
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
import { defineTable } from '@quickback/compiler';
export const rooms = sqliteTable('rooms', {
id: text('id').primaryKey(),
name: text('name').notNull(),
description: text('description'),
capacity: integer('capacity').notNull().default(10),
roomType: text('room_type').notNull(),
isActive: integer('is_active', { mode: 'boolean' }).notNull().default(true),
deactivationReason: text('deactivation_reason'),
// Ownership - required for firewall data isolation
organizationId: text('organization_id').notNull(),
});
export default defineTable(rooms, {
// 1. FIREWALL - Data isolation
firewall: { organization: {} },
// 2. GUARDS - Field modification rules
guards: {
createable: ["name", "description", "capacity", "roomType"],
updatable: ["name", "description", "capacity"],
protected: {
isActive: ["activate", "deactivate"], // Only via actions
},
},
// 3. CRUD - Role-based access control
crud: {
list: { access: { roles: ["owner", "admin", "member"] }, pageSize: 25 },
get: { access: { roles: ["owner", "admin", "member"] } },
create: { access: { roles: ["owner", "admin"] } },
update: { access: { roles: ["owner", "admin"] } },
delete: { access: { roles: ["owner", "admin"] }, mode: "soft" },
},
});
export type Room = typeof rooms.$inferSelect;What Each Layer Does
- Firewall: Automatically adds
WHERE organizationId = ?to every query. Users in Org A can never see Org B's data. - Guards: Controls which fields can be modified —
createablefor POST,updatablefor PATCH,protectedfor action-only fields. - CRUD Access: Role-based access control for each operation. Members can read, only admins can write.
Compile and Run
# Log in (first time only)
quickback login
# Compile your definitions
quickback compile
# Run locally
npm run devGenerated Endpoints
Quickback generates these endpoints from the example above:
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1/rooms | List rooms (owners, admins, members) |
GET | /api/v1/rooms/:id | Get single room |
POST | /api/v1/rooms | Create room (admins only) |
PATCH | /api/v1/rooms/:id | Update room (admins only) |
DELETE | /api/v1/rooms/:id | Soft delete room (admins only) |
Next Steps
- Template Walkthroughs — Detailed setup guides
- Full Example — Complete resource walkthrough
- Database Schema — Column types, relations, audit fields
- Firewall — Data isolation patterns
- Access — Role & condition-based control
- Guards — Field modification rules
- Masking — Field redaction for sensitive data
- Actions — Custom business logic endpoints