Skip to main content

cloudflare-storage

Use Cloudflare KV, R2 and D1 from a Worker. Binding config, Worker code, cf commands, local vs remote data, D1 migrations. Use when adding or changing storage bindings or schemas.

Source facts

Repository
codewhale-hq/codewhale-plugin-marketplace
Last source activity
October 6, 2026 at 23:05
Detected SKILL.md language
English
Stars
5
Forks
2

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
cloudflare-storage
description
Use Cloudflare KV, R2 and D1 from a Worker. Binding config, Worker code, cf commands, local vs remote data, D1 migrations. Use when adding or changing storage bindings or schemas.
# Cloudflare KV, R2 and D1 basics Local first: `cf dev` simulates the project's bindings through its adapter. Resource commands are remote unless a supported `--local` mode is explicitly selected. Consult `cf cli search` with an anonymous action/resource query and inspect the discovered command's help/schema; beta command names and flags are not interchangeable with Wrangler's. Remote writes require approval (`cloudflare-deploy`). Vite development data and cf local API data are separate stores; check the actual persistence directory before comparing results. Pick the store by access pattern: | Store | Good for | Not for | | --- | --- | --- | | KV | read-heavy config, cache, small values, eventually consistent | counters, anything needing read-your-write across regions | | R2 | files, blobs, uploads, S3-compatible access | relational queries | | D1 | relational data in SQLite, migrations, transactions via `batch` | very high write rates to one database, large blobs | | Durable Objects | per-entity coordination and strongly consistent state | bulk storage (see cloudflare-durable-objects) | ## KV Declare `CACHE` in `worker.env` with the current `bindings.kv` helper from `cf/config`, preserving the existing namespace ID. Validate typed options against the cf configuration reference and inspect dry-run bindings. ```ts await env.CACHE.put("user:1", JSON.stringify(user), { expirationTtl: 3600 }); const user = await env.CACHE.get("user:1", "json"); // null when missing const page = await env.CACHE.list({ prefix: "user:", limit: 100 }); ``` - Writes can take a while (60 seconds or more) to be visible in other locations; do not use KV where staleness is a bug. - `expirationTtl` has a documented minimum of 60 seconds. - Use `cf cli search "create a key value namespace"` or an equivalent anonymous query, then inspect the returned help/schema. Namespace creation is remote and needs approval; local KV writes require explicit `--local`. ## R2 Declare `FILES` with the current `bindings.r2` helper in `worker.env`; retain the existing bucket identity and check generated bindings. ```ts await env.FILES.put(key, request.body, { httpMetadata: { contentType: "image/png" } }); const obj = await env.FILES.get(key); // null when missing if (!obj) return new Response("Not found", { status: 404 }); return new Response(obj.body, { headers: { etag: obj.httpEtag } }); // elsewhere: await env.FILES.delete(key); ``` - Stream `request.body` into `put`; do not buffer large uploads in memory. - Validate keys from user input (no path tricks, enforce a prefix per user). - Discover cf R2 bucket/object commands through anonymous command search; creating a bucket or writing/deleting an object remotely requires approval. ## D1 Declare `DB` using the current `bindings.d1` helper in `worker.env`, keeping the existing database ID and generated environment types. Verify the helper's schema before adding migration options; do not copy legacy snake_case keys. ```ts const { results } = await env.DB.prepare("SELECT id, email FROM users WHERE org = ?1 LIMIT ?2") .bind(orgId, 50) .all(); const row = await env.DB.prepare("SELECT * FROM users WHERE id = ?1").bind(id).first(); await env.DB.batch([ env.DB.prepare("INSERT INTO audit(event) VALUES (?1)").bind("signup"), env.DB.prepare("UPDATE users SET active = 1 WHERE id = ?1").bind(id), ]); ``` - Always `bind()` user input; never concatenate it into SQL. - Schema changes stay in reviewed, numbered SQL migration files. Keep the framework's migration tool if it already owns ordering and receipts; inspect its generated SQL, apply it only to the local test store and run the tests. - Discover cf D1 query/migration commands and exact input shape with anonymous command search and help/schema. Never assume a Wrangler migration command exists in cf under the same name. - Production application is a data change: show SQL, database and account, get approval, and keep a restore plan. Prefer additive migrations. A DROP, table rebuild or unrestricted DELETE requires explicit data-loss approval. Check current D1 recovery/Time Travel availability rather than promising a retention window from memory. Always bind user values, even in CLI queries. ## Checklist - [ ] binding names are valid JS identifiers and match `Env` - [ ] generated binding types and project type check current - [ ] code handles `null` / missing results - [ ] local test ran against simulated storage - [ ] no remote write happened without a yes References: [cf local resources](https://developers.cloudflare.com/cf/projects/), [typed bindings](https://developers.cloudflare.com/cf/projects/cloudflare-config/).
View on GitHub