Bindings

A binding name never carries the project. It is a variable name inside your own Worker, and two projects cannot collide on it — only the resource it resolves to is scoped.

By capability

Every name here is held to the naming rules, the databases behind them carry these tables, what a Worker must declare is the Worker contract, and the class-migration half is Durable Objects.

CapabilityBindingKind
authDBD1
AUTH_RATE_LIMITERRate limitingThe coarse per-IP edge guard
paymentsDBD1
PAYMENTS_RECONCILEWorkflowOptional
storageDBD1
STORAGE_BUCKETR2
STORAGE_SWEEPWorkflowOptional
mediaDBD1
MEDIA_BUCKETR2
MEDIA_IMAGE_TO_TEXTWorkflowOptional
MEDIA_AUDIO_TRANSCRIBEWorkflowOptional
MEDIA_VIDEO_TRANSCRIBEWorkflowOptional
MEDIA_DOC_EXTRACTWorkflowOptional
emailDBD1
EMAIL_SUPPRESSIONSD1Shared across environments
EMAIL_SENDERWorkflow
vectorVECTORIZEVectorizeRemote
AIWorkers AIRemote
DBD1
VECTOR_REPROCESSWorkflowOptional
secretsSECRETSD1Its own database
SECRETS_ENCRYPTION_KEYSSecrets StoreThe master key
supportDBD1
SUPPORT_BUCKETR2Optional
SUPPORT_CLASSIFYWorkflowOptional
testersDBD1
TESTERS_DAILYWorkflowOptional
auditDBD1
ledgerDBD1
leaderboardDBD1
ratingDBD1
multiplayerSESSIONSDurable ObjectMultiplayerSession
DBD1
matchmakingDBD1
MATCHMAKINGKVRoom codes
QUEUEDurable ObjectMatchmakingQueue
PRESENCEDurable ObjectMatchmakingPresence
coreDBD1
CONTROL_PLANEKVOptional — only the KV replay backend
i18n, turnstile—No bindings at all

DB is shared on purpose

Most capabilities default to DB, the shared app database, so an admin Worker and an API Worker read the same rows without wiring.

One capability’s tables cannot collide with another’s, because every one is pithy_<capability>_*.

Two that are deliberately not DB

SECRETS is its own database, because the master key that opens its rows is per environment.

EMAIL_SUPPRESSIONS is shared across a project’s environments — because an unsubscribe has to apply everywhere, and somebody who opted out in production has not agreed to receive staging’s mail.

Optional means the capability works without it

A missing optional Workflow binding is a feature that does not run, not a Worker that will not boot.

Storage without its sweep still uploads; abandoned rows simply are not reclaimed. Media without its enrichment Workflows still stores files.

The exception that bites is core/missing_workflow_binding — a Workflow binding pointing at a host nothing has provisioned. That is the first-run surprise.

What pithy add can and cannot write

add writes bindings and touches no account. That is why adding a capability works offline, in CI, and without credentials.

Three kinds it cannot finish:

A vectorize entry needs an index_name that provisioning produces.

A workflows entry needs a name and a class_name, both per environment — and a partial entry stops wrangler loading the config at all, so add writes none.

A kv_namespaces entry has no name field, so add prints the name to create and you paste the id in.

Durable Object classes are exported from their own modules

export { MultiplayerSession } from "@pithy-sh/multiplayer/src/session/durableObject";
export { MatchmakingQueue } from "@pithy-sh/matchmaking/src/queue/durableObject";
export { MatchmakingPresence } from "@pithy-sh/matchmaking/src/presence/durableObject";

Each also needs a class-migration tag, in a different block, repeated per environment. A binding without the tag deploys a Worker whose class does not exist.

ESC