Quickback Docs

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/quickback

Create a Project

quickback create cloudflare my-app
cd my-app

This scaffolds a complete project with:

  • quickback.config.ts — Project configuration
  • quickback/features/ — Your table definitions
  • Example 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:

quickback/
├── quickback.config.ts
└── features/
    └── jobs/
        ├── jobs.ts             # Table + security config
        ├── applications.ts     # Related table + config
        ├── actions.ts          # Custom actions (optional)
        └── handlers/           # Action handlers (optional)
            └── close-job.ts

Complete Example

Here's a complete jobs table with all security layers:

// quickback/features/jobs/jobs.ts
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
import { defineTable } from '@quickback/compiler';

export const jobs = sqliteTable('jobs', {
  id: text('id').primaryKey(),
  title: text('title').notNull(),
  department: text('department').notNull(),
  status: text('status').notNull().default('draft'),  // draft, open, closed
  salaryMin: integer('salary_min'),
  salaryMax: integer('salary_max'),

  // Ownership - required for firewall data isolation
  organizationId: text('organization_id').notNull(),
});

export default defineTable(jobs, {
  // 1. FIREWALL - Data isolation
  firewall: { organization: {} },

  // 2. GUARDS - Field modification rules
  guards: {
    createable: ["title", "department", "status", "salaryMin", "salaryMax"],
    updatable: ["title", "department", "status"],
  },

  // 3. CRUD - Role-based access control
  crud: {
    list: { access: { roles: ["owner", "hiring-manager", "recruiter", "interviewer"] }, pageSize: 25 },
    get: { access: { roles: ["owner", "hiring-manager", "recruiter", "interviewer"] } },
    create: { access: { roles: ["owner", "hiring-manager"] } },
    update: { access: { roles: ["owner", "hiring-manager"] } },
    delete: { access: { roles: ["owner", "hiring-manager"] }, mode: "soft" },
  },
});

export type Job = typeof jobs.$inferSelect;

What Each Layer Does

  1. Firewall: Automatically adds WHERE organizationId = ? to every query. Users in Org A can never see Org B's data.
  2. Guards: Controls which fields can be modified — createable for POST, updatable for PATCH, protected for action-only fields.
  3. CRUD Access: Role-based access control for each operation. All roles can read, only hiring managers can write.

Compile and Run

# Log in (first time only)
quickback login

# Compile your definitions
quickback compile

# Run locally
npm run dev

Generated Endpoints

Quickback generates these endpoints from the example above:

MethodEndpointDescription
GET/api/v1/jobsList jobs (all roles)
GET/api/v1/jobs/:idGet single job
POST/api/v1/jobsCreate job (hiring managers only)
PATCH/api/v1/jobs/:idUpdate job (hiring managers only)
DELETE/api/v1/jobs/:idSoft delete job (hiring managers only)

Test Your API

After quickback compile and npm run dev, your API is running locally. Open a second terminal and try these requests:

# 1. Create a user account
curl -X POST http://localhost:8787/api/auth/sign-up/email \
  -H "Content-Type: application/json" \
  -d '{"email": "admin@example.com", "password": "securepassword123", "name": "Admin"}'

# 2. Sign in and get a session token
curl -X POST http://localhost:8787/api/auth/sign-in/email \
  -H "Content-Type: application/json" \
  -d '{"email": "admin@example.com", "password": "securepassword123"}'
# → Response includes a session token in Set-Cookie header

# 3. Create a record (use the session cookie from step 2)
curl -X POST http://localhost:8787/api/v1/jobs \
  -H "Content-Type: application/json" \
  -H "Cookie: better-auth.session_token=<token>" \
  -d '{"title": "Senior Engineer", "department": "Engineering", "status": "open"}'

# 4. List records
curl http://localhost:8787/api/v1/jobs \
  -H "Cookie: better-auth.session_token=<token>"

The port depends on your template: 8787 for Cloudflare (wrangler), 3000 for Bun. Check your terminal output for the exact URL.

Next Steps

See Also

  • Quickback Stack — The runtime environment where your compiled API runs (D1, KV, R2, auth)
  • Account UI — Pre-built authentication and account management UI
  • Using the API — CRUD endpoints, filtering, and batch operations

On this page