> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chardb.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Deploy

> Configure Cloudflare and deploy the Worker.

## Set production secrets

Authenticate Wrangler, then copy the generated environment template.

```bash theme={null}
bunx wrangler login
cp .env.example .env.local
```

Set `CHARDB_URL` to the public URL Wrangler prints for the Worker, usually `https://<worker-name>.<account-subdomain>.workers.dev`. If you use a custom domain, configure that route before bootstrapping. Replace both secret placeholders.

```dotenv .env.local theme={null}
CHARDB_URL=https://your-worker.example.com
CHARDB_ADMIN_TOKEN=replace-with-32-to-512-byte-secret
BETTER_AUTH_SECRET=replace-with-at-least-32-byte-secret
```

Do not commit `.env.local`. The bootstrap script sends both secrets through a mode-0600 temporary file, removes it, and never puts a secret in process arguments.

## First deploy

Create the external resources, then bootstrap the Worker. The bootstrap script runs type checks, tests, and both builds before it uploads.

```bash theme={null}
bun run setup:cloudflare
bun run deploy:bootstrap
```

`setup:cloudflare` creates or verifies the R2 bucket in `wrangler.toml`. It does not install an expiry rule: the private content-addressed objects are the authoritative file bytes. Vectorize needs the explicit setup shown in [Vectors](/vectors). `deploy:bootstrap` uploads the first Worker, waits for the packaged schema identity, and applies the migration.

## Later deploys

Use the routine release path when the resources already exist. It runs the same checks and builds before upload.

```bash theme={null}
bun run deploy
```

Routine `deploy` requires an existing Worker and refuses a package or migration mismatch.

<Note>
  Keep `CHARDB_ADMIN_TOKEN` separate from `BETTER_AUTH_SECRET`. The first authorizes maintenance operations. The second signs application sessions.
</Note>

## Cost boundary

CharDB adds no hosted-service fee. Cloudflare bills Workers, Durable Objects, R2, and Vectorize from the bindings and traffic in your application. One application mutation can cause several Durable Object calls and SQLite row operations.

File uploads write one content-addressed R2 object per unique payload digest, so identical payloads share bytes. Those objects do not expire automatically. Bytes left by rejected uploads or deleted files remain billable until provider-wide orphan collection is available. A completed restore also materializes one live key for each restored file until normal deletion removes it. Current evidence measures latency and operation counts, not a complete Cloudflare invoice. It does not collect every Worker CPU-ms, Durable Object duration, R2 GB-month, or Vectorize billing dimension.

## Recovery boundary

Capture a native SQLite recovery point after a healthy deploy and before a migration:

```bash theme={null}
bunx @chardb/core backups create --url https://your-worker.example.com --out recovery.json
```

Store the manifest outside the deployment. Restore validates the current topology, fences new traffic, and restarts the Catalog and every active shard at their recorded Durable Object PITR bookmarks:

```bash theme={null}
bunx @chardb/core backups restore --url https://your-worker.example.com --from recovery.json
```

Cloudflare retains Durable Object PITR history for 30 days. CharDB keeps authoritative R2 file bodies without automatic expiry. During restore it clears CharDB's current live R2 keys and tracked Vectorize records in signed, bounded turns, restarts every Durable Object, eagerly rebuilds authoritative files, and requeues authoritative vectors. The same manifest resumes after an unknown result. CharDB does not provide automatic regional failover or a production SLA.

Automatic resharding and range merging are unsupported.

For recovery, resharding, and availability limits, read [Plan ahead](/plan-ahead).

Read [Schema migrations](/schema-migrations) before changing a deployed table.
