workers
Core Workers fundamentals including handlers, configuration, and Service Bindings. Load when creating new Workers, configuring wrangler.jsonc, implementing fetch/scheduled/queue handlers, using Service Bindings for RPC, generating types with wrangler types, or building microservices.
What this skill does
# Cloudflare Workers
Essential patterns for building Cloudflare Workers applications with TypeScript, proper configuration, and Service Bindings for microservices.
## FIRST: Project Setup
Initialize a new Workers project:
```bash
npm create cloudflare@latest my-worker
# OR
wrangler init my-worker
```
**Minimal wrangler.jsonc:**
```jsonc
{
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2025-03-07",
"compatibility_flags": ["nodejs_compat"],
"observability": {
"enabled": true,
"head_sampling_rate": 1
}
}
```
## Code Standards
| Standard | Requirement | Notes |
|----------|-------------|-------|
| **Language** | TypeScript by default | JavaScript only if explicitly requested |
| **Module Format** | ES modules only | NEVER use Service Worker format |
| **Imports** | Always import types/classes | Must import all used methods |
| **File Structure** | Single file unless specified | Keep code in one file by default |
| **Dependencies** | Minimize external deps | Use official SDKs when available |
| **Native Bindings** | Not supported | Avoid FFI/C bindings |
| **Types** | Include TypeScript types | Define Env interface for bindings |
## Handler Patterns
### HTTP Request Handler (fetch)
```typescript
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
// Route handling
if (url.pathname === "/api/data") {
return handleAPI(request, env);
}
return new Response("Hello World!", {
headers: { "Content-Type": "text/plain" }
});
}
};
async function handleAPI(request: Request, env: Env): Promise<Response> {
// Validate request method
if (request.method !== "POST") {
return new Response("Method not allowed", { status: 405 });
}
try {
const data = await request.json();
// Process data...
return Response.json({ success: true, data });
} catch (error) {
return Response.json(
{ error: "Invalid JSON" },
{ status: 400 }
);
}
}
```
### Scheduled Handler (cron)
```typescript
export default {
async scheduled(event: ScheduledEvent, env: Env, ctx: ExecutionContext): Promise<void> {
// Run scheduled tasks
console.log("Cron triggered:", new Date(event.scheduledTime).toISOString());
// Use waitUntil for background work
ctx.waitUntil(performCleanup(env));
}
};
async function performCleanup(env: Env): Promise<void> {
// Background cleanup logic
console.log("Cleanup completed");
}
```
**wrangler.jsonc configuration:**
```jsonc
{
"triggers": {
"crons": ["0 */6 * * *"] // Every 6 hours
}
}
```
### Queue Consumer Handler
```typescript
export default {
async queue(batch: MessageBatch<QueueMessage>, env: Env, ctx: ExecutionContext): Promise<void> {
for (const message of batch.messages) {
try {
await processMessage(message.body, env);
message.ack();
} catch (error) {
console.error("Message processing failed:", error);
message.retry();
}
}
}
};
type QueueMessage = {
id: string;
data: unknown;
};
async function processMessage(body: QueueMessage, env: Env): Promise<void> {
// Process queue message
console.log("Processing message:", body.id);
}
```
## Auto-Generate Environment Types
**RECOMMENDED:** Use `wrangler types` to automatically generate your `Env` interface from your `wrangler.jsonc`:
```bash
# Generate types from wrangler.jsonc
npx wrangler types
# Output to custom path
npx wrangler types ./types/env.d.ts
# Include runtime types (Wrangler >= 3.66.0)
npx wrangler types --experimental-include-runtime
```
This generates a `worker-configuration.d.ts` file with:
- **Env interface** matching all your bindings (KV, R2, D1, secrets, etc.)
- **Runtime types** matching your `compatibility_date` and `compatibility_flags`
- **Service binding types** with full RPC method signatures
**Add to tsconfig.json:**
```jsonc
{
"compilerOptions": {
"types": ["@cloudflare/workers-types", "./worker-configuration"]
}
}
```
**When to regenerate:**
- After adding/removing bindings in wrangler.jsonc
- After changing compatibility_date or compatibility_flags
- After modifying .dev.vars (secrets)
- Before deploying (run in CI/CD)
**Example generated Env interface:**
```typescript
// worker-configuration.d.ts (auto-generated)
interface Env {
// From wrangler.jsonc bindings
MY_KV: KVNamespace;
MY_BUCKET: R2Bucket;
DB: D1Database;
COUNTER: DurableObjectNamespace;
AUTH_SERVICE: Service<typeof AuthService>;
AI: Ai;
MY_QUEUE: Queue;
// From .dev.vars (secrets)
DATABASE_URL: string;
API_KEY: string;
// From wrangler.jsonc vars
ENVIRONMENT: "development" | "staging" | "production";
API_VERSION: string;
}
```
## Secrets Management
**CRITICAL: Never put secrets in wrangler.jsonc!** Secrets must be encrypted and hidden.
### Secrets vs Environment Variables
| Type | Storage | Use For | Visibility |
|------|---------|---------|------------|
| **vars** (wrangler.jsonc) | Plaintext | Non-sensitive config (URLs, flags) | ✅ Visible |
| **secrets** | Encrypted | API keys, passwords, tokens | ❌ Hidden |
### Local Development with .dev.vars
Create a `.dev.vars` file for local secrets (NEVER commit this file):
```bash
# .dev.vars (add to .gitignore)
DATABASE_URL="postgresql://localhost:5432/dev"
API_KEY="dev-key-12345"
STRIPE_SECRET="sk_test_..."
```
### CI/CD Best Practice: Empty .dev.vars
For CI/CD and type generation, commit a `.dev.vars` with **empty values**:
```bash
# .dev.vars (committed to git)
# Real values set via: wrangler secret put
DATABASE_URL=""
API_KEY=""
STRIPE_SECRET=""
```
**Why this works:**
- `wrangler types` reads `.dev.vars` to generate `Env` types
- Empty values create correct TypeScript types
- CI/CD can run type checking without real secrets
- Production secrets are set via `wrangler secret put` or dashboard
### Setting Production Secrets
**Via Wrangler:**
```bash
# Add/update secret (deploys immediately)
npx wrangler secret put API_KEY
# You'll be prompted for value
# List secrets (values never shown)
npx wrangler secret list
# Delete secret
npx wrangler secret delete API_KEY
```
**Via Dashboard:**
Workers & Pages → Your Worker → Settings → Variables and Secrets → Add → Secret
**Accessing secrets in code:**
```typescript
interface Env {
DATABASE_URL: string;
API_KEY: string;
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Access secrets from env (same as regular env vars)
const db = new Database(env.DATABASE_URL);
// Validate API key
const key = request.headers.get("x-api-key");
if (key !== env.API_KEY) {
return new Response("Unauthorized", { status: 401 });
}
return Response.json({ success: true });
}
};
```
### Secret Store (Account-Level Secrets)
For secrets shared across multiple Workers:
```jsonc
{
"secrets_store_secrets": [
{
"binding": "SHARED_API_KEY",
"store_id": "abc123def456",
"secret_name": "GLOBAL_API_KEY"
}
]
}
```
**Accessing Secret Store:**
```typescript
interface Env {
SHARED_API_KEY: {
get(): Promise<string>;
};
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Secret Store requires .get() call
const apiKey = await env.SHARED_API_KEY.get();
return Response.json({ success: true });
}
};
```
See [references/secrets.md](references/secrets.md) for complete secrets management guide.
## wrangler.jsonc Configuration
Complete example with common bindings:
```jsonc
{
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2025-03-07",
"compatibility_flags": ["nodejs_compat"],
"observability": {
"enabled": true,
"head_sampling_rate": 1
},
"vars": {
"ENVIRONMENT": "production"
},
"kv_namespaces": [
{ "binding": "MY_KV", "id": "your-kv-id" }
],
"rRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.