Agent Quickstart

Copy-paste this page into your AI agent's chat to give it full context on teenybase.

Introduction

You are working with teenybase, a backend-as-a-service on Cloudflare Workers. The entire backend is defined in a single teenybase.ts config file — no backend code.

Install CLI

bash
npm install -g teenybase

This gives you the teeny command globally.

Setup

There are two paths depending on whether this is a new project or an existing one. Infer which from conversation context (e.g. the user already has a package.json, or says "add a backend to my app" → Option B). If unclear, ask: "Are we starting a new project or adding teenybase to an existing one?"

Option A: New project

bash
teeny create my-app -t with-auth -y
cd my-app

Important: Always pass -t and -y when running non-interactively (scripts, CI, coding agents). Without them, teeny create launches arrow-key prompts that hang when stdin is not a TTY.

FlagWhat it does
-t, --template <template>Set the project template. Values: with-auth (users table + auth + rules) or blank (empty project).
-y, --yesSkip all confirmation prompts and use defaults.

If neither flag is given, the CLI prompts interactively for template and deploy target.

This creates the directory, scaffolds all files, and runs npm install. You're ready to go.

Files created:

  • package.json — deps: teenybase, hono ^4, devDeps: wrangler ^4, typescript ^5, @cloudflare/workers-types ^4
  • teenybase.ts — backend config (tables, auth, rules)
  • src/index.ts — worker entry point (imports teenybase, wires up Database + extensions)
  • wrangler.jsonc — Cloudflare Workers config with D1 binding PRIMARY_DB
  • .dev.vars — local secrets: JWT_SECRET, JWT_SECRET_USERS, ADMIN_JWT_SECRET, ADMIN_SERVICE_TOKEN, POCKET_UI_VIEWER_PASSWORD, POCKET_UI_EDITOR_PASSWORD
  • worker-configuration.d.ts — TypeScript type for CloudflareBindings
  • tsconfig.json — includes path alias "virtual:teenybase": ["./teenybase"]
  • migrations/ — empty, auto-populated by teeny generate
  • .gitignore — ignores node_modules, .local-persist, .dev.vars, .prod.vars, migrations

Start the local dev server:

bash
teeny generate --local
teeny deploy --local
teeny dev --local

API is at http://localhost:8787/api/v1.

Option B: Add to existing project

bash
npm install teenybase hono
npm install -D wrangler @cloudflare/workers-types typescript
teeny init

teeny init detects existing files and only creates what's missing. It will not overwrite your package.json — it only creates one if none exists. If you already have a tsconfig.json, it patches in the "virtual:teenybase": ["./teenybase"] path alias without replacing it.

Important: Since teeny init does not modify an existing package.json, you must install the dependencies yourself (the npm install lines above).

After init, start the local dev server:

bash
teeny generate --local
teeny deploy --local
teeny dev --local

Key files

FilePurpose
teenybase.tsBackend config — tables, fields, auth, rules, actions. In most apps, this is the main file you edit.
src/index.tsWorker entry point. Usually unchanged unless you need custom routes or R2 storage.
wrangler.jsoncCloudflare Workers config, D1/R2 bindings
.dev.varsLocal secrets (6 keys: JWT_SECRET, JWT_SECRET_USERS, ADMIN_JWT_SECRET, ADMIN_SERVICE_TOKEN, POCKET_UI_VIEWER_PASSWORD, POCKET_UI_EDITOR_PASSWORD)
.prod.varsProduction secrets (same keys, strong values). Not auto-created — copy from .dev.vars.
migrations/Auto-generated SQL. Don't edit manually.

CLI commands

bash
teeny create <name> [-t <tpl>] [-y]  # Scaffold new project (runs npm install)
teeny init [-t <tpl>] [-y]           # Add teenybase to existing project
teeny generate --local           # Generate migrations from config changes
teeny deploy --local             # Apply migrations to local database
teeny dev --local                # Start local dev server (port 8787)
teeny deploy --remote            # Deploy to Teenybase Cloud
teeny register                   # Create Teenybase Cloud account (free)
teeny login                      # Log in
teeny status                     # Show deployed URL and status
teeny secrets --remote --upload  # Upload .prod.vars to production
teeny list                       # List deployed workers
teeny delete [name]              # Delete a deployed worker
teeny --help                     # List commands and options

Config format

ts
import { DatabaseSettings } from 'teenybase'
import { baseFields, authFields, createdTrigger, updatedTrigger } from 'teenybase/scaffolds/fields'

export default {
  appUrl: 'http://localhost:8787',
  jwtSecret: '$JWT_SECRET',        // Resolved from .dev.vars / .prod.vars
  appName: 'My App',
  tables: [
    {
      name: 'users',
      autoSetUid: true,
      fields: [...baseFields, ...authFields],
      triggers: [createdTrigger, updatedTrigger],
      extensions: [
        { name: 'auth', jwtSecret: '$JWT_SECRET_USERS', jwtTokenDuration: 3600, maxTokenRefresh: 5 },
        { name: 'rules', createRule: 'true', viewRule: 'auth.uid == id', listRule: 'auth.uid == id', updateRule: 'auth.uid == id', deleteRule: 'auth.uid == id' },
      ],
    },
    {
      name: 'posts',
      autoSetUid: true,
      fields: [
        ...baseFields,
        { name: 'title', type: 'text', sqlType: 'text' },
        { name: 'body', type: 'text', sqlType: 'text' },
        { name: 'author', type: 'text', sqlType: 'text' },
        { name: 'published', type: 'bool', sqlType: 'boolean', default: '0' },
      ],
      triggers: [createdTrigger, updatedTrigger],
      extensions: [
        { name: 'rules', listRule: 'published == true', viewRule: 'published == true', createRule: 'auth.uid == author', updateRule: 'auth.uid == author', deleteRule: 'auth.uid == author' },
      ],
    },
  ],
} satisfies DatabaseSettings

If you keep the default scaffold from teeny create, it also includes authCookie: { name: 'teeny_auth' } and passwordConfirmSuffix: 'Confirm' on the users auth extension. authCookie enables cookie-based sessions for OAuth redirect callbacks and any SSR layer you add; sign-up and password-reset requests must include passwordConfirm.

In the posts example above, set author to the signed-in user's record.id on insert so the ownership rules line up with auth.uid == author.

API endpoints

Base URL: http://localhost:8787/api/v1 (local). For deployed apps, run teeny status and use the exact URL it prints, then append /api/v1.

CRUD:

POST /table/{table}/insert      { "values": {...}, "returning": "*" }
GET|POST /table/{table}/select  ?where=...&order=...&limit=...
GET|POST /table/{table}/list    Same as select but returns { items, total }
GET  /table/{table}/view/{id}
POST /table/{table}/update      { "where": "id == '...'", "setValues": {...} }
POST /table/{table}/edit/{id}   { "field": "value" }
POST /table/{table}/delete      { "where": "id == '...'" }

Auth:

POST /table/{table}/auth/sign-up              { "username", "email", "password", "name" }
POST /table/{table}/auth/login-password       { "identity", "password" }
POST /table/{table}/auth/refresh-token        { "refresh_token" }
POST /table/{table}/auth/request-password-reset   { "email" }
POST /table/{table}/auth/confirm-password-reset   { "token", "password" }
POST /table/{table}/auth/request-verification     Authorization: Bearer <token>
POST /table/{table}/auth/confirm-verification     { "token" }
POST /table/{table}/auth/logout                   Authorization: Bearer <token>
POST /auth/logout                                 Clears auth cookie only

Auth header: Authorization: Bearer <token>

Other:

GET  /health
GET  /doc/ui          # Swagger UI
GET  /doc             # OpenAPI 3.1.0 JSON

Workflow

  1. Edit teenybase.ts
  2. Run teeny generate --local (generates migrations)
  3. Run teeny deploy --local (applies migrations)
  4. Run teeny dev --local (starts server)
  5. Test with curl or frontend
  6. When ready: teeny deploy --remote