Skip to content

Cloudflare compatibility

This reference records the Cloudflare-compatible surface Nimbus serves today. It is intentionally narrower than a generic “Cloudflare-compatible” claim: only the Workers KV REST data plane is served. Anything not listed as served should be assumed unserved.

Cloudflare routes are served by default on the main HTTP listener; opt out with --no-cloudflare. The routes are gated on a Cloudflare configuration being present, which it is by default. A non-loopback --host is refused unless --allow-network is also set, matching the network-bind posture of the other adapters.

This Cloudflare KV data plane — the GET/PUT/DELETE REST API under /client/v4/accounts/... — is distinct from the RESP nimbus kv surface documented at Nimbus KV compatibility. They are separate protocols backed by separate wire formats.

The Cloudflare surface is default-on but early and partial. Workers KV over REST is the only Cloudflare data plane served today. Durable Objects, D1, and R2 are not served: Durable Objects has a compatibility-test substrate that no production front door can construct, and D1 and R2 exist only as parsed wrangler bindings in the configuration registry. The Not served section lists each unserved family.

The KV REST API is mounted on the main listener. Routes follow the Cloudflare account-scoped path shape.

MethodPathBehavior
GET/client/v4/accounts/{account_id}/storage/kv/namespaces/{namespace_id}/values/{key}Reads a value. Responds application/octet-stream; 404 when the key is absent.
PUT/client/v4/accounts/{account_id}/storage/kv/namespaces/{namespace_id}/values/{key}Writes a value with optional expiration, expirationTtl, and metadata query parameters.
DELETE/client/v4/accounts/{account_id}/storage/kv/namespaces/{namespace_id}/values/{key}Deletes a key. Deleting an absent key succeeds.
GET/client/v4/accounts/{account_id}/storage/kv/namespaces/{namespace_id}/metadata/{key}Returns the JSON metadata stored with a key.
GET/client/v4/accounts/{account_id}/storage/kv/namespaces/{namespace_id}/keysLists keys with optional prefix, cursor, and limit query parameters.

Metadata, list, write-acknowledgement, and error responses use the Cloudflare API envelope shape (success, errors, messages, result); value reads (GET .../values/{key}) return the raw stored bytes as application/octet-stream. Errors carry a numeric code and message. List responses add result_info with a cursor and a list_complete flag — list_complete is false and a cursor is returned when a full page is read.

ParameterApplies toBehavior
expirationPUT valueAbsolute expiry in seconds since the Unix epoch.
expirationTtlPUT valueRelative time-to-live in seconds; must be at least 60.
metadataPUT valueJSON string stored alongside the value and returned by the metadata and list routes.
prefixGET keysRestricts the listing to keys under a prefix.
cursorGET keysOpaque continuation token from a prior list page.
limitGET keysPage size; defaults to 1000 and may not exceed 1000.

expiration and expirationTtl are mutually exclusive; supplying both is rejected. Listed keys report their expiration (in seconds) and metadata when present.

LimitValue
Maximum key length512 bytes
Maximum value size25 MiB
Maximum metadata size1024 bytes
Minimum expirationTtl60 seconds
Default and maximum list limit1000

Keys must be non-empty and must not contain NUL. Values and metadata over their limits are rejected with a 400.

Every KV REST request authenticates with an Authorization: Bearer header whose token is ACCESS_KEY_ID:SECRET. The id and secret resolve to a tenant through the adapter’s signed-access-key registry. By default this is the same generated wire access key the DynamoDB listener uses, bound to the tenant default; the credential is persisted with the other wire credentials in the data directory. A missing header, a non-Bearer scheme, a token without the id:secret shape, an unrecognized id, or a mismatched secret is rejected with 401.

The {namespace_id} path segment resolves against the KV namespace bindings in the active configuration. It matches a binding by its binding name, its id, or its preview_id. When no KV namespace bindings are configured, the {namespace_id} value is used directly as the namespace. When bindings are configured and none matches, the request is rejected with 404. Stored keys are namespaced, so keys in one namespace are not visible through another.

At startup the adapter reads a wrangler configuration from the app directory when one is present, checking wrangler.jsonc, wrangler.json, then wrangler.toml. JSONC comments and trailing commas are stripped before parsing. The parsed bindings populate a configuration registry with four families: KV namespaces, Durable Objects, D1 databases, and R2 buckets.

Only the KV namespace bindings drive a served data plane (namespace resolution, above). The Durable Object, D1, and R2 bindings are parsed and held in the registry but back no HTTP surface.

Cloudflare familyState
Durable ObjectsA compatibility-test substrate covers per-instance activation records, transactional storage, alarms, and hibernated-WebSocket records. Its local process lane and local-wall deadline are not distributed authority. Nimbus exposes no production construction path or served Durable Object data plane; enablement requires distributed per-object placement and storage-atomic epoch fencing.
D1Parsed as wrangler d1_databases bindings into the configuration registry only. No D1 HTTP data plane.
R2Parsed as wrangler r2_buckets bindings into the configuration registry only. No R2 HTTP data plane.
Workers script executionNot served. Nimbus does not run Worker scripts against these bindings.