Skip to main content
Reference Last updated: 31 March 2026

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 init embeds config from CLI flags
  • npx cf-monitor deploy re-reads cf-monitor.yaml and re-embeds on every deploy
  • Secrets (tokens, webhooks) remain as wrangler secrets — the config JSON only contains $VARIABLE_NAME references
  • Backward compatible: if CF_MONITOR_CONFIG is 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 /usage and npx 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:

MetricFree plan dailyPaid plan daily
d1_writes10,0001,333,333
d1_reads166,66716,666,667
kv_writes1,00026,667
kv_reads33,333333,333
ai_neurons33,333333,333
r2_class_a3,33333,333
r2_class_b33,333333,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
  ...
Was this helpful?

Related Articles