---
title: "Agent Quickstart"
description: "One page to paste into Claude Code, Cursor or Codex: how to run the teenybase CLI, set up a project, write teenybase.ts, test locally and deploy."
url: https://teenybase.com/docs/getting-started/quickstart-agent
last_updated: 2026-10-26
---

> Documentation index: https://teenybase.com/llms.txt lists every teenybase docs page with a link to its Markdown version. All docs in one file: https://teenybase.com/llms-full.txt

# 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 framework that deploys to the user's own Cloudflare account (Workers + D1 + R2). The entire backend is defined in a single `teenybase.ts` config file — no backend code.

### Run the CLI

Run every command as `npx teenybase <command>`. After `npm install -g teenybase`, `teeny <command>` works too. Never use `npx teeny`: it downloads an unrelated npm package named `teeny`.

Early (v0.1): APIs may change before 1.0.

### 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
npx teenybase 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, a command that needs to ask a question fails with exit code 1 when stdin is not a TTY, and the error names the flag to pass.

| Flag | What it does |
|---|---|
| `-t, --template <template>` | Set the project template. Values: `with-auth` (users table + auth + rules) or `blank` (empty project). |
| `-y, --yes` | Skip 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 `generate` / `deploy`
- `.gitignore` — ignores `node_modules`, `.local-persist`, `.dev.vars`, `.prod.vars`, `migrations`

Apply the migrations and start the local dev server:

```bash
npx teenybase deploy --local --yes
npx teenybase dev
```

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
npx teenybase init -y
```

`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 `init` does not modify an existing `package.json`, you must install the dependencies yourself (the `npm install` lines above).

After init, apply the migrations and start the local dev server:

```bash
npx teenybase deploy --local --yes
npx teenybase dev
```

### Key files

| File | Purpose |
|---|---|
| `teenybase.ts` | Backend config — tables, fields, auth, rules, actions. In most apps, this is the main file you edit. |
| `src/index.ts` | Worker entry point. Usually unchanged unless you need custom routes or R2 storage. |
| `wrangler.jsonc` | Cloudflare Workers config, D1/R2 bindings |
| `.dev.vars` | Local secrets (6 keys: JWT_SECRET, JWT_SECRET_USERS, ADMIN_JWT_SECRET, ADMIN_SERVICE_TOKEN, POCKET_UI_VIEWER_PASSWORD, POCKET_UI_EDITOR_PASSWORD) |
| `.prod.vars` | Production secrets (same keys). Generated with random values on the first remote deploy. Gitignored. |
| `migrations/` | Auto-generated SQL. Don't edit manually. |

### CLI commands

```bash
npx teenybase create <name> [-t <tpl>] [-y]  # Scaffold new project (runs npm install)
npx teenybase init [-t <tpl>] [-y]           # Add teenybase to existing project
npx teenybase generate --local               # Generate migrations from config changes
npx teenybase deploy --local --yes           # Generate + apply migrations to the local database
npx teenybase dev                            # Start local dev server (port 8787)
npx wrangler login                           # One-time: authenticate with Cloudflare
npx teenybase deploy --remote --yes          # Deploy to the user's Cloudflare account
npx teenybase secrets --remote --upload      # Upload .prod.vars to production
npx teenybase logs                           # Stream logs from the deployed worker
npx teenybase --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, use the worker URL printed by `npx teenybase deploy --remote` (also saved in `infra.jsonc`) and 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", "passwordConfirm", "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", "passwordConfirm" }
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 `npx teenybase deploy --local --yes` (generates and applies migrations)
3. Keep `npx teenybase dev` running (it reloads after each local deploy)
4. Test with curl or the frontend
5. When ready: `npx wrangler login` (once), then `npx teenybase deploy --remote --yes`
