# Deploying

Building in [Quickback Start](https://start.quickback.dev) instead of locally? You can also [deploy straight from the browser](/start/deploy-browser) — no CLI needed.

A freshly compiled project's `wrangler.toml` contains **placeholder resource ids** — the compiler can't know your D1 database ids or KV namespace id until those resources exist in your Cloudflare account. Historically that meant a manual dance: `wrangler d1 create`, copy the id, paste it into `quickback.config.ts`, repeat for every database, recompile, deploy.

`quickback deploy` does the whole dance for you:

```bash
cd my-app && quickback deploy
```

## What it does

1. **Preflight** — verifies `wrangler` is runnable (via `npx`) and authenticated with Cloudflare (`wrangler whoami`). Log in with `npx wrangler login` or set `CLOUDFLARE_API_TOKEN`.
2. **Compiles first if needed** — if the project has never compiled (no `wrangler.toml`), it runs the same flow as `quickback compile` before planning anything.
3. **Plans from wrangler.toml** — reads the generated `wrangler.toml` and finds every resource whose id is still a placeholder:
   - **D1 databases** — auth, features, files, webhooks, and audit databases (whichever your project's features pull in; split-database projects get one entry each)
   - **KV namespace** — the `KV` binding used for rate limiting and session overflow
   - **R2 buckets** — file-storage buckets (R2 is referenced by name, so buckets are simply ensured to exist)
4. **Creates what's missing** — `wrangler d1 create <name>`, `wrangler kv namespace create <BINDING>`, `wrangler r2 bucket create <name>`. Resources are named from your project name exactly the way the compiler names them (`my-app-auth`, `my-app-features`, `my-app-files`, `my-app-KV`, …). If a resource with the expected name already exists in your account, its id is reused instead of creating a duplicate.
5. **Writes ids back into quickback.config.ts** — a surgical, formatting-preserving edit of your `providers.database.config` (and `providers.storage.config` for the KV id when you declare a `cloudflare-kv` storage provider). Comments, indentation, and every other key are left untouched. Works with both authoring styles:

   ```ts
   // defineDatabase(...) wrapper
   database: defineDatabase("cloudflare-d1", {
     splitDatabases: true,
     authDatabaseId: "…",       // ← inserted/updated here
     featuresDatabaseId: "…",
   }),

   // plain object form
   database: {
     name: "cloudflare-d1",
     config: {
       authDatabaseId: "…",     // ← or here
     },
   },
   ```

6. **Recompiles** — so `wrangler.toml` regenerates with the real ids.
7. **Applies D1 migrations remotely** — `wrangler d1 migrations apply <db> --remote` for each database that has pending migration files (each database's `migrations_dir` comes straight from `wrangler.toml`).
8. **Deploys** — `wrangler deploy`, streaming wrangler's output.

## Idempotent by design

Run it again any time. When every id is real, there's nothing to create — the command goes straight to compile → migrations → deploy. It's a perfectly good everyday "ship it" command, not just a first-deploy tool.

## Flags

| Flag | Effect |
|------|--------|
| `--dry-run` | Print the provisioning plan (what would be created vs. what's already set) and exit. Creates nothing. |
| `--skip-deploy` | Provision resources + sync ids + recompile, but skip migrations and the deploy itself. |
| `--force` | Overwrite a config id that differs from what Cloudflare reports. Without it, a mismatch prints both values and aborts — never silently overwritten. |
| `--verbose` | Detailed remote compile failure output (same as `quickback compile --verbose`). |

```bash
# See the plan without touching your account
quickback deploy --dry-run

# Provision + write ids only; deploy later
quickback deploy --skip-deploy
```

## Conflicting ids

If `quickback.config.ts` already carries a real id for a resource and Cloudflare reports a different one for the same-named resource, `quickback deploy` prints both and stops:

```
✖ Config ids differ from what Cloudflare reports:
    providers.database.config.authDatabaseId
      in quickback.config.ts: 13b688c8-…
      from Cloudflare:        f6b8f9a0-…
```

Re-run with `--force` to take Cloudflare's value, or fix the config by hand.

## Notes

- **Security-audit database** — projects using unsafe, `PUBLIC`, or hard-delete actions get an `AUDIT_DB` D1. Compile emits a placeholder id; `quickback deploy` creates the database and writes `auditDatabaseId` back, same as AUTH_DB / features DB. Direct `wrangler deploy` of the placeholder fails Cloudflare 10021 — use `quickback deploy`.
- **Neon projects** — `quickback deploy` does not apply Postgres migrations. Run `npm run db:migrate` (needs `DATABASE_MIGRATION_URL`) before traffic hits the worker, or use the generated project's `npm run deploy` script which chains both.
- **Hyperdrive** — a Hyperdrive binding can't be auto-created (it needs your database connection string). Create it with `wrangler hyperdrive create <name> --connection-string=… --caching-disabled` and set `providers.database.config.hyperdrive.id`.
- **Two logins** — the compile step uses your Quickback account (`quickback login`); resource creation and deploy use your wrangler credentials.
