Initial commit
This commit is contained in:
665
skills/skill/references/bindings-complete-guide.md
Normal file
665
skills/skill/references/bindings-complete-guide.md
Normal file
@@ -0,0 +1,665 @@
|
||||
# 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:**
|
||||
|
||||
```toml
|
||||
[[kv_namespaces]]
|
||||
binding = "MY_KV"
|
||||
id = "your-namespace-id"
|
||||
preview_id = "preview-namespace-id" # For local dev
|
||||
```
|
||||
|
||||
**API:**
|
||||
|
||||
```typescript
|
||||
// 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:**
|
||||
|
||||
```toml
|
||||
[[d1_databases]]
|
||||
binding = "DB"
|
||||
database_name = "my-database"
|
||||
database_id = "your-database-id"
|
||||
```
|
||||
|
||||
**API:**
|
||||
|
||||
```typescript
|
||||
// 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:**
|
||||
|
||||
```toml
|
||||
[[r2_buckets]]
|
||||
binding = "MY_BUCKET"
|
||||
bucket_name = "my-bucket"
|
||||
jurisdiction = "eu" # Optional: eu or fedramp
|
||||
```
|
||||
|
||||
**API:**
|
||||
|
||||
```typescript
|
||||
// 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:**
|
||||
|
||||
```toml
|
||||
[[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:**
|
||||
|
||||
```typescript
|
||||
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:**
|
||||
|
||||
```typescript
|
||||
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:**
|
||||
|
||||
```typescript
|
||||
// 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:**
|
||||
|
||||
```toml
|
||||
[[queues.producers]]
|
||||
binding = "MY_QUEUE"
|
||||
queue = "my-queue"
|
||||
|
||||
[[queues.consumers]]
|
||||
queue = "my-queue"
|
||||
max_batch_size = 100
|
||||
max_batch_timeout = 30
|
||||
```
|
||||
|
||||
**Producer (send messages):**
|
||||
|
||||
```typescript
|
||||
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):**
|
||||
|
||||
```typescript
|
||||
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:**
|
||||
|
||||
```toml
|
||||
[ai]
|
||||
binding = "AI"
|
||||
```
|
||||
|
||||
**API:**
|
||||
|
||||
```typescript
|
||||
// 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:**
|
||||
|
||||
```toml
|
||||
[[vectorize]]
|
||||
binding = "VECTORIZE"
|
||||
index_name = "my-index"
|
||||
```
|
||||
|
||||
**API:**
|
||||
|
||||
```typescript
|
||||
// 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:**
|
||||
|
||||
```toml
|
||||
[[hyperdrive]]
|
||||
binding = "HYPERDRIVE"
|
||||
id = "your-hyperdrive-id"
|
||||
```
|
||||
|
||||
**Usage with postgres:**
|
||||
|
||||
```typescript
|
||||
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:**
|
||||
|
||||
```toml
|
||||
[[services]]
|
||||
binding = "AUTH_SERVICE"
|
||||
service = "auth-worker"
|
||||
environment = "production"
|
||||
```
|
||||
|
||||
**HTTP-based:**
|
||||
|
||||
```typescript
|
||||
const response = await env.AUTH_SERVICE.fetch(new Request("http://auth/verify"));
|
||||
```
|
||||
|
||||
**RPC-based (recommended):**
|
||||
|
||||
```typescript
|
||||
// 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.
|
||||
|
||||
```toml
|
||||
[[analytics_engine_datasets]]
|
||||
binding = "ANALYTICS"
|
||||
```
|
||||
|
||||
```typescript
|
||||
env.ANALYTICS.writeDataPoint({
|
||||
blobs: ["user-123", "click"],
|
||||
doubles: [1.5],
|
||||
indexes: ["button-1"],
|
||||
});
|
||||
```
|
||||
|
||||
### Browser Rendering
|
||||
|
||||
Control headless browsers.
|
||||
|
||||
```toml
|
||||
browser = { binding = "BROWSER" }
|
||||
```
|
||||
|
||||
```typescript
|
||||
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.
|
||||
|
||||
```toml
|
||||
[[unsafe.bindings]]
|
||||
name = "RATE_LIMITER"
|
||||
type = "ratelimit"
|
||||
namespace_id = "your-namespace-id"
|
||||
simple = { limit = 100, period = 60 }
|
||||
```
|
||||
|
||||
```typescript
|
||||
const { success } = await env.RATE_LIMITER.limit({ key: userId });
|
||||
if (!success) {
|
||||
return new Response("Rate limited", { status: 429 });
|
||||
}
|
||||
```
|
||||
|
||||
### mTLS
|
||||
|
||||
Present client certificates.
|
||||
|
||||
```toml
|
||||
[[mtls_certificates]]
|
||||
binding = "CERT"
|
||||
certificate_id = "your-cert-id"
|
||||
```
|
||||
|
||||
```typescript
|
||||
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:
|
||||
|
||||
```typescript
|
||||
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:
|
||||
|
||||
```bash
|
||||
# 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/
|
||||
Reference in New Issue
Block a user