13 KiB
Complete Bindings Guide
Bindings are how Workers connect to Cloudflare resources and external services. They provide zero-latency access to storage, databases, queues, and other services.
Storage Bindings
KV (Key-Value Storage)
Global, low-latency, eventually consistent key-value storage.
Best for:
- Configuration data
- User sessions
- Cache
- Small objects (<25 MB)
Configuration:
[[kv_namespaces]]
binding = "MY_KV"
id = "your-namespace-id"
preview_id = "preview-namespace-id" # For local dev
API:
// Write
await env.MY_KV.put("key", "value");
await env.MY_KV.put("key", "value", {
expirationTtl: 3600, // Expire in 1 hour
metadata: { user: "123" }
});
// Read
const value = await env.MY_KV.get("key");
const json = await env.MY_KV.get("key", "json");
const buffer = await env.MY_KV.get("key", "arrayBuffer");
// With metadata
const { value, metadata } = await env.MY_KV.getWithMetadata("key");
// Delete
await env.MY_KV.delete("key");
// List keys
const keys = await env.MY_KV.list({ prefix: "user:" });
Limits:
- Key size: 512 bytes
- Value size: 25 MB
- Write rate: 1 write/second per key (eventually consistent)
- Read rate: unlimited
D1 (SQL Database)
Serverless SQLite database built on SQLite.
Best for:
- Structured data
- Relational data
- Complex queries
- ACID transactions
Configuration:
[[d1_databases]]
binding = "DB"
database_name = "my-database"
database_id = "your-database-id"
API:
// Query with bind parameters
const result = await env.DB.prepare(
"SELECT * FROM users WHERE id = ?"
).bind(userId).all();
// Insert
await env.DB.prepare(
"INSERT INTO users (name, email) VALUES (?, ?)"
).bind(name, email).run();
// Update
await env.DB.prepare(
"UPDATE users SET last_login = ? WHERE id = ?"
).bind(new Date().toISOString(), userId).run();
// Transaction
const results = await env.DB.batch([
env.DB.prepare("INSERT INTO users (name) VALUES (?)").bind("Alice"),
env.DB.prepare("INSERT INTO users (name) VALUES (?)").bind("Bob"),
]);
// First row only
const user = await env.DB.prepare(
"SELECT * FROM users WHERE id = ?"
).bind(userId).first();
Features:
- Read replication (low latency reads globally)
- Time Travel (restore to any point in last 30 days)
- Backups
- Migrations via Wrangler
Limits:
- Database size: 10 GB (Paid), 500 MB (Free)
- Rows read: 25M/day (Paid), 5M/day (Free)
- Rows written: 50M/day (Paid), 100K/day (Free)
R2 (Object Storage)
S3-compatible object storage with zero egress fees.
Best for:
- Large files
- Media storage
- Static assets
- Backups
Configuration:
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-bucket"
jurisdiction = "eu" # Optional: eu or fedramp
API:
// Put object
await env.MY_BUCKET.put("file.txt", "contents", {
httpMetadata: {
contentType: "text/plain",
cacheControl: "max-age=3600",
},
customMetadata: {
user: "123",
},
});
// Put from stream
await env.MY_BUCKET.put("large-file.bin", request.body);
// Get object
const object = await env.MY_BUCKET.get("file.txt");
if (object) {
const text = await object.text();
const buffer = await object.arrayBuffer();
const stream = object.body; // ReadableStream
// Metadata
console.log(object.httpMetadata);
console.log(object.customMetadata);
}
// Get with range
const object = await env.MY_BUCKET.get("file.txt", {
range: { offset: 0, length: 1024 }
});
// Head (metadata only)
const object = await env.MY_BUCKET.head("file.txt");
// Delete
await env.MY_BUCKET.delete("file.txt");
// List objects
const objects = await env.MY_BUCKET.list({
prefix: "images/",
limit: 1000,
});
// Multipart upload (for large files)
const upload = await env.MY_BUCKET.createMultipartUpload("large.bin");
const part = await upload.uploadPart(1, data);
await upload.complete([part]);
Features:
- Automatic multipart uploads
- Object versioning
- Event notifications
- Public buckets
- Custom domains
Limits:
- Max object size: 5 TB
- Storage: unlimited
- Operations: unlimited
Compute Bindings
Durable Objects
Strongly consistent, coordinated stateful objects with SQLite storage.
Best for:
- Real-time collaboration
- WebSocket servers
- Coordination
- Strong consistency
- Per-user/per-room state
Configuration:
[[durable_objects.bindings]]
name = "COUNTER"
class_name = "Counter"
script_name = "my-worker" # Optional: if in different Worker
[[migrations]]
tag = "v1"
new_classes = ["Counter"]
Durable Object Class:
export class Counter {
state: DurableObjectState;
constructor(state: DurableObjectState, env: Env) {
this.state = state;
}
async fetch(request: Request): Promise<Response> {
// Get from storage
let count = (await this.state.storage.get("count")) || 0;
// Increment
count++;
// Put to storage
await this.state.storage.put("count", count);
return Response.json({ count });
}
// Alarms (scheduled actions)
async alarm() {
await this.state.storage.delete("count");
}
}
Worker Usage:
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Get Durable Object ID
const id = env.COUNTER.idFromName("global-counter");
// Get stub (reference)
const stub = env.COUNTER.get(id);
// Call via fetch
return stub.fetch(request);
},
};
Storage API:
// Single operations
await this.state.storage.put("key", "value");
const value = await this.state.storage.get("key");
await this.state.storage.delete("key");
// Batch operations
await this.state.storage.put({
key1: "value1",
key2: "value2",
});
const values = await this.state.storage.get(["key1", "key2"]);
// List
const entries = await this.state.storage.list();
// SQL (new)
const result = await this.state.storage.sql.exec(
"SELECT * FROM users WHERE id = ?", userId
);
Features:
- SQLite-backed storage
- Automatic persistence
- Alarms (scheduled actions)
- WebSocket Hibernation
- Point-in-time recovery
Queues
Message queuing for async processing with guaranteed delivery.
Best for:
- Background jobs
- Async processing
- Decoupling services
- Retry logic
Configuration:
[[queues.producers]]
binding = "MY_QUEUE"
queue = "my-queue"
[[queues.consumers]]
queue = "my-queue"
max_batch_size = 100
max_batch_timeout = 30
Producer (send messages):
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Send single message
await env.MY_QUEUE.send({ userId: 123, action: "process" });
// Send batch
await env.MY_QUEUE.sendBatch([
{ body: { userId: 123 } },
{ body: { userId: 456 } },
]);
return Response.json({ queued: true });
},
};
Consumer (receive messages):
export default {
async queue(batch: MessageBatch<any>, env: Env): Promise<void> {
for (const message of batch.messages) {
try {
await processMessage(message.body);
message.ack(); // Mark as processed
} catch (error) {
message.retry(); // Retry later
}
}
},
};
Features:
- Guaranteed delivery
- Automatic retries
- Dead letter queues
- Batch processing
- Pull consumers (API-based)
AI & ML Bindings
Workers AI
Run AI models directly from Workers.
Best for:
- Text generation (LLMs)
- Embeddings
- Image generation
- Speech recognition
- Translation
Configuration:
[ai]
binding = "AI"
API:
// Text generation
const response = await env.AI.run("@cf/meta/llama-3-8b-instruct", {
messages: [
{ role: "system", content: "You are a helpful assistant" },
{ role: "user", content: "What is Cloudflare?" }
],
});
// Embeddings
const embeddings = await env.AI.run("@cf/baai/bge-base-en-v1.5", {
text: "The quick brown fox jumps over the lazy dog",
});
// Image generation
const image = await env.AI.run("@cf/stabilityai/stable-diffusion-xl-base-1.0", {
prompt: "A sunset over the ocean",
});
// Speech to text
const result = await env.AI.run("@cf/openai/whisper", {
audio: audioData,
});
// Streaming
const stream = await env.AI.run("@cf/meta/llama-3-8b-instruct", {
messages: [{ role: "user", content: "Tell me a story" }],
stream: true,
});
Vectorize
Vector database for similarity search.
Best for:
- Semantic search
- RAG (Retrieval Augmented Generation)
- Recommendations
- Embeddings storage
Configuration:
[[vectorize]]
binding = "VECTORIZE"
index_name = "my-index"
API:
// Insert vectors
await env.VECTORIZE.insert([
{ id: "1", values: [0.1, 0.2, ...], metadata: { text: "..." } },
{ id: "2", values: [0.3, 0.4, ...], metadata: { text: "..." } },
]);
// Query (similarity search)
const results = await env.VECTORIZE.query(
[0.15, 0.25, ...], // Query vector
{
topK: 5,
returnMetadata: true,
}
);
// With metadata filtering
const results = await env.VECTORIZE.query(vector, {
topK: 5,
filter: { category: "technology" },
});
Database Bindings
Hyperdrive
Accelerate access to existing databases via connection pooling and caching.
Best for:
- Connecting to existing Postgres/MySQL
- Reducing latency to traditional databases
- Connection pooling
Configuration:
[[hyperdrive]]
binding = "HYPERDRIVE"
id = "your-hyperdrive-id"
Usage with postgres:
import { Client } from "pg";
const client = new Client({
connectionString: env.HYPERDRIVE.connectionString,
});
await client.connect();
const result = await client.query("SELECT * FROM users");
await client.end();
Features:
- Connection pooling
- Query caching
- Read replicas support
Service Bindings
Call other Workers via RPC or HTTP.
Configuration:
[[services]]
binding = "AUTH_SERVICE"
service = "auth-worker"
environment = "production"
HTTP-based:
const response = await env.AUTH_SERVICE.fetch(new Request("http://auth/verify"));
RPC-based (recommended):
// In auth-worker
export class AuthService extends WorkerEntrypoint {
async verifyToken(token: string): Promise<boolean> {
// Verify logic
return true;
}
}
// In calling worker
const isValid = await env.AUTH_SERVICE.verifyToken(token);
Additional Bindings
Analytics Engine
Write custom analytics and metrics.
[[analytics_engine_datasets]]
binding = "ANALYTICS"
env.ANALYTICS.writeDataPoint({
blobs: ["user-123", "click"],
doubles: [1.5],
indexes: ["button-1"],
});
Browser Rendering
Control headless browsers.
browser = { binding = "BROWSER" }
const browser = await puppeteer.launch(env.BROWSER);
const page = await browser.newPage();
await page.goto("https://example.com");
const screenshot = await page.screenshot();
Rate Limiting
Built-in rate limiting.
[[unsafe.bindings]]
name = "RATE_LIMITER"
type = "ratelimit"
namespace_id = "your-namespace-id"
simple = { limit = 100, period = 60 }
const { success } = await env.RATE_LIMITER.limit({ key: userId });
if (!success) {
return new Response("Rate limited", { status: 429 });
}
mTLS
Present client certificates.
[[mtls_certificates]]
binding = "CERT"
certificate_id = "your-cert-id"
const response = await fetch("https://api.example.com", {
certificate: env.CERT,
});
Best Practices
Binding Selection
- KV: Configuration, sessions, cache
- D1: Structured data, complex queries
- R2: Large files, media, backups
- Durable Objects: Real-time, strong consistency, coordination
- Queues: Background jobs, async processing
- Workers AI: AI/ML inference
- Vectorize: Similarity search, RAG
Performance
- Use
ctx.waitUntil()for non-critical writes - Batch operations when possible
- Use appropriate consistency models
- Cache frequently accessed data
Error Handling
Always handle errors from bindings:
try {
const value = await env.MY_KV.get("key");
} catch (error) {
// Handle error
console.error("KV error:", error);
return new Response("Service unavailable", { status: 503 });
}
Local Development
Use Wrangler for local testing with bindings:
# KV
wrangler kv:namespace create MY_KV --preview
# D1
wrangler d1 create my-database
# Local dev with bindings
wrangler dev
Additional Resources
- Bindings Reference: https://developers.cloudflare.com/workers/runtime-apis/bindings/
- KV: https://developers.cloudflare.com/kv/
- D1: https://developers.cloudflare.com/d1/
- R2: https://developers.cloudflare.com/r2/
- Durable Objects: https://developers.cloudflare.com/durable-objects/
- Queues: https://developers.cloudflare.com/queues/
- Workers AI: https://developers.cloudflare.com/workers-ai/
- Vectorize: https://developers.cloudflare.com/vectorize/