---
title: "Config Cheat Sheet"
description: "A one-page summary of teenybase.ts: top-level settings, tables, fields, the auth and rules extensions, auth providers, email and actions."
url: https://teenybase.com/docs/config
last_updated: 2026-04-21
---

> 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

# Config Reference

Your backend is defined in `teenybase.ts`. This file exports a `DatabaseSettings` object.

## Top-level settings

```ts
export default {
  appUrl: 'http://localhost:8787',       // Base URL (used in OAuth redirects, emails)
  appName: 'My App',                     // Used in email templates
  jwtSecret: '$JWT_SECRET',              // Global JWT signing secret
  jwtIssuer: '$db',                      // JWT issuer claim (optional)
  tables: [],                            // Table definitions
  authCookie: { name: 'teeny_auth' },    // Optional, needed for OAuth redirect flows and SSR cookie sessions
  authProviders: [],                     // OAuth providers (optional)
  // email: { ... },                     // Email sending config (optional)
  actions: [],                           // Server-side actions (optional)
} satisfies DatabaseSettings
```

Values prefixed with `$` (like `$JWT_SECRET`) are environment variables. They're read from `.dev.vars` when running locally and from `.prod.vars` in production. This keeps secrets out of your config file.

## Tables

```ts
{
  name: 'posts',
  autoSetUid: true,          // Auto-generate unique ID on insert
  fields: [...],
  triggers: [...],
  extensions: [...],
  r2Base: 'posts',           // R2 path prefix for file fields (optional)
  autoDeleteR2Files: true,   // Delete files when record deleted (optional)
}
```

## Fields

```ts
{ name: 'title', type: 'text', sqlType: 'text' }
{ name: 'count', type: 'number', sqlType: 'integer', default: '0' }
{ name: 'published', type: 'bool', sqlType: 'boolean', default: '0' }
{ name: 'data', type: 'json', sqlType: 'text' }
{ name: 'avatar', type: 'file', sqlType: 'text' }
```

Use scaffolds for common patterns:

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

// baseFields: id, created, updated
// authFields: username, email, email_verified, password, password_salt, name, avatar, role, meta
```

## Auth extension

Adds sign-up, login, password reset, email verification, and OAuth endpoints to a table.

```ts
{
  name: 'auth',
  jwtSecret: '$JWT_SECRET_USERS',   // Table-specific secret (combined with global)
  jwtTokenDuration: 3600,           // Token TTL in seconds (default: 3600)
  maxTokenRefresh: 5,               // Required. Set 0 for unlimited refreshes
  passwordConfirmSuffix: 'Confirm', // Optional. Requires passwordConfirm on sign-up/reset
} as TableAuthExtensionData
```

## Rules extension

Row-level security. Each rule is an expression evaluated on every request to decide whether the operation is allowed. The expression can reference `auth.uid` (the signed-in user's ID), `auth.verified` (email verified), `auth.role` (role), and any column on the current row.

```ts
{
  name: 'rules',
  listRule: 'published == true',           // Who can list records
  viewRule: 'published == true',           // Who can view a single record
  createRule: 'auth.uid != null',          // Who can insert
  updateRule: 'auth.uid == author',        // Who can update
  deleteRule: 'auth.uid == author',        // Who can delete
} as TableRulesExtensionData
```

Special values:
- `'true'` — allow everyone, including unauthenticated users
- `'false'` or omitted — block everyone (admins still bypass rules)
- `auth.uid` — the signed-in user's record ID (null if not signed in)
- `auth.verified` — true if the user's email is verified
- `auth.role` — the user's role/audience claim from their JWT

## Auth providers

```ts
authProviders: [
  {
    name: 'google',                          // Preset: google, github, discord, linkedin
    clientId: '$GOOGLE_CLIENT_ID',
    clientSecret: '$GOOGLE_CLIENT_SECRET',   // Omit for One Tap only
    redirectUrl: 'https://myapp.com/dashboard',
  },
]
```

For browser-based OAuth redirect flows, also configure `authCookie`:

```ts
authCookie: {
  name: 'teeny_auth',
  httpOnly: true,
  secure: true,
  sameSite: 'Lax',
  path: '/',
}
```

Redirect flows (`/auth/oauth/...`) and `google-login` set this cookie automatically when configured. JSON auth endpoints like `login-password` and `sign-up` still return tokens in the response body — your frontend stores them as bearer tokens, or your SSR layer sets the cookie itself using the returned token.

## Email

```ts
email: {
  from: 'My App <noreply@myapp.com>',
  variables: {
    company_name: 'My App',
    company_url: 'https://myapp.com',
    company_address: '123 Main St, San Francisco, CA',
    company_copyright: 'Copyright 2026 My App',
    support_email: 'support@myapp.com',
  },
  resend: {
    RESEND_API_KEY: '$RESEND_API_KEY',
  },
}
```

Use `mailgun` instead of `resend` if you prefer Mailgun. Email verification and password reset only work when this section is configured.

Practical notes:

- the `from` address should belong to a sender/domain your email provider accepts
- local testing is easiest with `mock: true`
- the `request-password-reset` and `confirm-password-reset` routes are only mounted when `email` is configured

For a full setup and test flow, see [Email Verification & Password Reset](https://teenybase.com/docs/guides/email-flows).

## Actions

Server-side logic callable via `POST /api/v1/action/{name}`.

```ts
actions: [
  {
    name: 'increment-views',
    params: { post_id: 'string' },
    sql: sql`UPDATE posts SET views = views + 1 WHERE id = ${sqlValue(':post_id')}`,
  },
]
```
