# Worker bindings

> Inspect what your live Worker can use, connect KV, buckets and email, and understand missing values before changing code.

Source: https://docs.fortly.com/deploy/bindings

A binding is a resource or value your Worker receives on `env`. Open **Deployments → Bindings** to inspect the live release. The config describes the connection; the binding's data and account-level setup are managed separately.

## Find the resource behind a binding

| Binding | Configure it | Manage it |
| --- | --- | --- |
| Static assets | `assets.binding` in wrangler config | Deploy the asset directory with the release. |
| Key-value | `kv_namespaces` | Open the exact namespace in **Storage → Key-value**. |
| Object bucket | `r2_buckets` | Open its folder in **Storage → Files**. |
| Email | `send_email` | Finish domain and destination setup under account **Email**. |
| Cron Trigger | `triggers.crons` | Inspect, pause or resume under **Schedules**. |
| Rate limiter | `ratelimits` | Configure the key limit and window in wrangler config. |
| Config value | `vars` | Deploy config changes, or override the value in **Variables**. |
| Secret | **Variables** | Set a runtime or build-and-runtime value with the required name. |

The workspace shows live-release bindings, not an undeployed config file or a failed release. A project with no live release has no live binding inventory. A static release has no Worker `env`.

## Connect several services

```jsonc title="wrangler.jsonc"
{
  "name": "my-app",
  "main": "src/index.js",
  "kv_namespaces": [{ "binding": "CACHE", "id": "cache" }],
  "r2_buckets": [{ "binding": "UPLOADS", "bucket_name": "uploads" }],
  "send_email": [{ "name": "EMAIL" }],
  "triggers": { "crons": ["0 3 * * *"] }
}
```

Deploy the config with your supported hand-written Worker, then check **Bindings**. Existing data is not copied from Cloudflare. Set secrets separately and verify email setup before expecting delivery. See the [Cloudflare compatibility matrix](https://docs.fortly.com/migrate/cloudflare#workers-written-with-wrangler) for the supported runtime and binding differences.

## Understand readiness

**Ready** means the resource is connected; it does not prove your application has useful data in it. A new namespace or bucket can be empty. Counts and sizes may be unavailable when the storage listing cannot be read.

**Missing** on a secret means the live Worker expects a value that is no longer set. **Overridden** on a config variable means a value in **Variables** takes precedence. Edit the variable's runtime scope when the Worker needs it during requests.

Email needs more than a binding declaration. Its console readiness checks provider availability, verified sending domains, the binding's sender and recipient restrictions, confirmed destinations and remaining monthly allowance. Follow the displayed next action under [Email](https://docs.fortly.com/email); adding a different confirmed recipient does not satisfy a binding restricted to one address.

Cron Triggers use the live config's `scheduled()` handler, not a public HTTP route. Pausing one preserves its history; removing it means editing `triggers.crons` and deploying again. See [Schedules](https://docs.fortly.com/deploy/schedules#worker-cron-triggers).

## Use a rate limiter

A supported wrangler `ratelimits` binding exposes `env.<binding>.limit({ key })`, returning `{ success }`. The configured limit applies per key in fixed windows of 10 or 60 seconds. Your code chooses a key and handles refusal; the binding does not authenticate the caller for you.

```js
const result = await env.RATE_LIMITER.limit({ key: "contact-form" });
if (!result.success) return new Response("Try again later", { status: 429 });
```

Choose a trusted key appropriate to the workload and your request environment. Do not use this as an atomic counter or assume another provider's global distribution semantics. The live binding inventory shows the configured limit and period.

## Inspect from the API

```bash
curl https://api.fortly.com/projects/my-app-ada/bindings \
  -H "Authorization: Bearer $FORTLY_TOKEN"
```

The response includes `deployment` and `bindings`. For a Worker it also includes `worker: true` and `framework`; static releases report `worker: false`. Binding rows have `name`, `kind` and `state`, with details such as `namespace`, `bucket`, `objects`, `bytes`, `limit`, `period` or `destination` for the relevant kind. Secret values are not included.

This endpoint is an inventory, not an email-send authorization check: its email state does not evaluate every sender restriction, provider setting or quota. Read [Email API](https://docs.fortly.com/api/email) and handle errors from `send()` as documented. To change a binding declaration, deploy updated config; this GET route does not mutate it.

## Keep the storage models separate

PostgreSQL is for relational records and queries. [KV](https://docs.fortly.com/kv) holds small values with optional expiry. [Files and R2-compatible buckets](https://docs.fortly.com/files#buckets-for-a-worker) hold objects. [Point-in-time recovery](https://docs.fortly.com/data/backups) restores the project's PostgreSQL database, not KV, bucket contents or account email settings.
