Configuration Reference
cf-monitor uses two configuration surfaces: cf-monitor.yaml for the monitor worker, and MonitorConfig for the SDK wrapper.
cf-monitor uses two configuration surfaces: cf-monitor.yaml for the monitor worker, and MonitorConfig for the SDK wrapper.
Configuration at Runtime
Since v0.3.6, cf-monitor.yaml is the actual runtime config source — not just documentation.
Flow: cf-monitor.yaml → CLI embeds as CF_MONITOR_CONFIG JSON var in wrangler.jsonc → worker calls enrichEnv() at startup → parseConfig() resolves $SECRET references against env → handlers use env.* as before.
npx cf-monitor initembeds config from CLI flagsnpx cf-monitor deployre-readscf-monitor.yamland re-embeds on every deploy- Secrets (tokens, webhooks) remain as wrangler secrets — the config JSON only contains
$VARIABLE_NAMEreferences - Backward compatible: if
CF_MONITOR_CONFIGis absent (older deployments),enrichEnv()is a no-op
Precedence: direct env var/secret > resolved config > undefined. Manual wrangler secret put values always win over config.
cf-monitor.yaml
Generated by npx cf-monitor init. Validated against cf-monitor.schema.json.
account (required)
account:
name: my-project # Human-readable account name
cloudflare_account_id: "55a0bf6d..." # 32-char hex account ID
The cloudflare_account_id supports environment variable references: $CLOUDFLARE_ACCOUNT_ID.
github (optional)
github:
repo: "owner/repo" # GitHub repo for error issues
token: $GITHUB_TOKEN # PAT with repo or issues:write scope
webhook_secret: $GITHUB_WEBHOOK_SECRET # For bidirectional issue sync
When configured, cf-monitor creates GitHub issues for captured errors with priority labels (cf:priority:p0 through cf:priority:p4).
alerts (optional)
alerts:
slack_webhook_url: $SLACK_WEBHOOK_URL # Slack incoming webhook
Slack alerts are sent for budget warnings (70%/90%), circuit breaker trips (100%), gap alerts, and cost spike detections. All alerts are deduplicated via KV.
monitoring (optional)
monitoring:
gap_detection_minutes: 15 # How often to check for gaps (5-60, default 15)
heartbeat_url: "https://..." # Gatus/uptime monitor heartbeat URL
heartbeat_token: $GATUS_TOKEN # Bearer token for heartbeat
spike_threshold: 2.0 # Cost spike multiplier (>1.5, default 2.0)
Plan detection (automatic)
cf-monitor automatically detects your Workers plan (Free or Paid) via the Cloudflare Subscriptions API. This is used to:
- Select correct default budgets when auto-seeding (Free plan limits are ~10x lower than Paid)
- Show plan allowances in
GET /usageandnpx cf-monitor usage - Calculate ”% of plan used” in the usage dashboard
No configuration needed. If your API token includes Account Settings: Read permission (#billing:read), plan detection works automatically. If not, cf-monitor defaults to Workers Paid plan budgets (conservative — won’t under-protect).
The detected plan is cached in KV for 24 hours (config:plan key).
Billing period (automatic)
When plan detection succeeds, cf-monitor also caches the billing period (start/end dates). Monthly budget tracking uses the billing period start date instead of calendar month boundaries, so budget enforcement aligns with your actual CF invoice.
For example, if your billing period runs from the 2nd to the 2nd, monthly budget KV keys use YYYY-MM-DD format (e.g. 2026-03-02) instead of YYYY-MM.
Cached in KV for 32 days (config:billing_period key). Falls back to calendar month (YYYY-MM) if billing period is unavailable.
budgets (optional)
budgets:
daily:
d1_writes: 50000
d1_reads: 500000
kv_writes: 10000
kv_reads: 100000
ai_requests: 1000
r2_class_a: 5000
queue_messages: 50000
vectorize_queries: 5000
monthly:
d1_writes: 1000000
kv_writes: 200000
If omitted, cf-monitor auto-calculates sensible defaults based on your Cloudflare plan:
| Metric | Free plan daily | Paid plan daily |
|---|---|---|
d1_writes | 10,000 | 1,333,333 |
d1_reads | 166,667 | 16,666,667 |
kv_writes | 1,000 | 26,667 |
kv_reads | 33,333 | 333,333 |
ai_neurons | 33,333 | 333,333 |
r2_class_a | 3,333 | 33,333 |
r2_class_b | 33,333 | 333,333 |
exclude (optional)
exclude:
- "test-*" # Skip workers matching these patterns
- "dev-*"
ai (optional)
ai:
enabled: false # Master switch for AI features
pattern_discovery: false # AI error pattern detection
health_reports: false # Natural language health summaries
coverage_auditor: false # AI integration scoring
model: "deepseek-chat" # AI model to use
AI features are disabled by default and require explicit opt-in.
SDK Options (MonitorConfig)
These options are passed to the monitor() wrapper in your worker code.
Handler functions
monitor({
fetch: (request, env, ctx) => Response, // HTTP handler
scheduled: (controller, env, ctx) => void, // Cron handler
queue: (batch, env, ctx) => void, // Queue handler
tail: (events, env, ctx) => void, // Tail handler (passthrough)
})
Worker identification
monitor({
workerName: 'my-worker', // Explicit name (highest priority)
// Detection chain: workerName > env.WORKER_NAME > env.name > 'worker'
})
Feature ID control
// Option 1: Single ID for the entire worker
monitor({ featureId: 'my-worker:all' })
// Option 2: Prefix for auto-generated IDs
monitor({ featurePrefix: 'platform' })
// Generates: platform:fetch:GET:api-items, platform:cron:0-*-*-*-*
// Option 3: Explicit route map
monitor({
features: {
'POST /api/scan': 'scanner:social',
'GET /health': false, // Exclude from tracking
'0 2 * * *': 'cron:harvest',
},
})
Precedence: featureId > features map > auto-generate with featurePrefix or workerName.
Path normalisation: auto-generated feature IDs strip numeric segments (/users/123 becomes users), UUIDs, and limit to 2 path segments.
Per-invocation limits
monitor({
limits: {
d1Writes: 500, // Default: 1000
d1Reads: 2000, // Default: 5000
kvWrites: 100, // Default: 200
kvReads: 500, // Default: 1000
aiRequests: 20, // Default: 50
r2ClassA: 50, // Default: 100
queueMessages: 200, // Default: 500
},
})
When a limit is exceeded, RequestBudgetExceededError is thrown immediately. This is the first line of defence — it stops runaway loops on the very first request.
Error and CB handlers
monitor({
onCircuitBreaker: (err) => {
// err.featureId, err.level ('feature'|'account'|'global'), err.reason
return new Response('Service temporarily unavailable', { status: 503 });
},
onError: (error, handler) => {
// handler is 'fetch' | 'scheduled' | 'queue'
console.error(`[${handler}] ${error}`);
return new Response('Internal error', { status: 500 });
},
})
Binding exclusion
monitor({
excludeBindings: ['MY_CUSTOM_STORE'], // Skip proxy wrapping for these env keys
fetch: handler,
})
Use when custom env objects accidentally match CF binding method signatures (e.g. an object with get(), put(), delete(), list() methods). See Security — Binding detection.
Options
monitor({
failOpen: true, // Default: true. SDK errors never break consumer.
autoHeartbeat: true, // Default: true. Ping Gatus after successful cron.
healthEndpoint: '/_monitor/health', // Default path. Set false to disable.
})
Environment Variables
cf-monitor.yaml supports $ENV_VAR syntax for secrets:
github:
token: $GITHUB_TOKEN # Reads from environment at runtime
alerts:
slack_webhook_url: $SLACK_WEBHOOK # Any env var name works
Set secrets on the deployed worker:
npx cf-monitor secret set CLOUDFLARE_API_TOKEN # Required — GraphQL, discovery, plan detection
npx cf-monitor secret set ADMIN_TOKEN # Recommended — protects /admin/* endpoints
npx cf-monitor secret set GITHUB_TOKEN # Optional — error issue creation
npx cf-monitor secret set SLACK_WEBHOOK_URL # Optional — budget/error alerts
npx cf-monitor secret set GITHUB_WEBHOOK_SECRET # Optional — webhook signature verification
npx cf-monitor secret set GATUS_TOKEN # Optional — heartbeat auth
See Security — Secrets management for minimum scopes and permissions.
JSON Schema Validation
The config file is validated against cf-monitor.schema.json. IDE support:
# yaml-language-server: $schema=./node_modules/@littlebearapps/cf-monitor/cf-monitor.schema.json
account:
name: my-project
...