Environment and bindings

Cloudflare runtime configuration for the Clay backend lives in apps/backend/wrangler.toml. This page is the canonical reference for what is currently declared, the rules for adding new variables or bindings, and the secret-handling guardrails that apply to all Cloudflare surfaces.
The backend has not yet adopted a typed environment module such as src/env.ts. When one is added, it should be described here and referenced from the Worker entry point. The wrangler TypeScript types can be regenerated with pnpm --filter @clay/backend types:wrangler, which writes worker-configuration.d.ts for editor IntelliSense.

Current state

apps/backend/wrangler.toml declares the Worker identity, the entry point, the compatibility date, and a single variable. No Hyperdrive, KV, R2, AI, D1, Durable Object, or Queues bindings are configured today.
name = "clay-backend"
main = "src/index.ts"
compatibility_date = "2026-07-07"

[vars]
APP_ENV = "development"

Variables

Variables declared under [vars] are read from env inside the Worker and are committed to source control. They are the right place for non-sensitive configuration that needs to be consistent across local development, preview, and production.
NameTypeDefaultPurpose
APP_ENVstring"development"Application environment tag, surfaced through the runtime so handlers can branch on local vs deployed behavior.
Variables are non-secret by definition. Anything that should never appear in git history belongs in a secret, not a [vars] entry.

Bindings

The Worker currently declares no bindings. Concretely, none of the following sections appear in apps/backend/wrangler.toml:
  • [[hyperdrive]] — Hyperdrive (Cloudflare’s database connection pooler for the Worker runtime)
  • [[kv_namespaces]] — Workers KV
  • [[r2_buckets]] — R2 object storage
  • [ai] — Workers AI
  • [[d1_databases]] — D1 (SQLite on the edge)
  • [[durable_objects.bindings]] — Durable Object namespaces
  • [[queues.producers]] / [[queues.consumers]] — Queues producers and consumers
  • [[services]] — service bindings to other Workers
  • [[analytics_engine_datasets]] — Workers Analytics Engine datasets
Any code path that depends on a binding must be added together with the binding entry. A handler that reaches for an absent binding will fail at runtime; documenting an “intended” binding here is not sufficient on its own.
Do not pre-document or pre-stub bindings. A future-binding entry in this file only becomes authoritative once the matching wrangler.toml block exists and the Worker code consumes it.

Adding a binding

Cloudflare runtime config must remain explicit and live in the owning app directory. Backends configure their Workers in apps/backend/wrangler.toml; Pages sites configure themselves in their own wrangler.toml.
1

Pick the binding kind and binding name

Match the binding kind to the runtime need (Hyperdrive for database access, KV for low-latency reads, R2 for blob storage, AI for inference). Pick an explicit, multi-word binding name such as HYPERDRIVE or OPPORTUNITY_CACHE, not DB or CACHE.
2

Declare it in apps/backend/wrangler.toml

Add the binding block under the top-level table. Keep all binding declarations in a single file rather than scattering them across env-specific overrides unless the override is required.
3

Consume it from src/index.ts

Read the binding through the typed Cloudflare env interface. Validate the binding name exists at module load so a missing binding fails fast on deploy rather than in production traffic.
4

Regenerate the wrangler types

Run pnpm --filter @clay/backend types:wrangler so worker-configuration.d.ts reflects the new binding. Without this, downstream consumers see the binding as unknown.
5

Update this page

Add a row to the Bindings table that names the binding, the wrangler block it comes from, the consuming code path, and any secret that backs it.
Prefer Wrangler’s environment-specific overrides ([env.staging], [env.production]) only when the binding’s identifier or region genuinely differs by environment. Avoid them when the binding name and target are stable across all envs.

Secret handling

Secrets belong to Cloudflare’s secret store, never to wrangler.toml and never to source control. The backend Worker, the landing Pages project, and the specs Pages project each have their own secret namespace.
1

Set secrets through Wrangler

Use wrangler secret put NAME per environment. The secret is encrypted at rest and is not visible in the dashboard without explicit retrieval.
2

Read them through env

Inside the Worker, access secrets via the typed env argument. Treat the value as a plain string and validate it at the boundary with Zod before passing it to a downstream client.
3

Never commit a secret

Do not paste real connection strings, API keys, OAuth client secrets, or webhook signing keys into files under apps/, packages/, docs/, or anywhere tracked by Git. Do not rely on .gitignore alone — assume anything typed into a tracked file will eventually be published.
4

Reference rules

Database URLs are especially sensitive because they combine credentials and topology. Hyperdrive is the intended Worker runtime boundary so a single reference string replaces raw URLs at the edge.
Database URLs are secrets. They must never appear in wrangler.toml, in committed examples, in fixture files, or in CI logs. When database access lands, configure it through Hyperdrive so the Worker never holds a raw connection string.

Future bindings

The backend team has identified Hyperdrive, KV, R2, and AI as the binding kinds the platform is likely to need. Treat these as intended only — they become implemented once both the wrangler.toml block and the Worker code exist.
Binding kindIntended purposeStatus
HyperdriveThe Worker runtime connection boundary for the primary relational database. Replaces raw database URLs at the edge.Intended. Not declared. Becomes authoritative once [[hyperdrive]] appears in wrangler.toml and a route reads from env.HYPERDRIVE.
KVLow-latency reads for opportunity metadata, personality caches, or rate-limit buckets.Intended. Not declared. Becomes authoritative once [[kv_namespaces]] appears and a route reads from it.
R2Object storage for generated 3D assets, large media, and long-lived archives.Intended. Not declared. Becomes authoritative once [[r2_buckets]] appears and a route reads from it.
AIWorkers AI binding for inference-backed features that should not pay the round-trip cost of an external model API.Intended. Not declared. Becomes authoritative once [ai] appears and a route calls env.AI.
“Intended” bindings must not be pre-stubbed in the codebase. Adding a placeholder binding without a consumer produces dead config; adding a consumer without a binding produces runtime failures. Land the wrangler block and the consumer in the same change.

Backend overview

The Hono + OpenAPI contract that runs on top of these bindings.

Deploy

How wrangler deploy and the per-surface pnpm cf:deploy scripts publish these bindings.

Architecture

The Turborepo surface layout the backend Worker lives inside.

API reference

The implemented HTTP routes and Zod schemas exposed through this Worker.