Cloudflare Workers
Sync KeyEnv secrets to Cloudflare Workers.
Cloudflare Workers Integration
Sync secrets from KeyEnv to your Cloudflare Workers.
Prerequisites
- Cloudflare account with Workers enabled
- Wrangler CLI installed
- KeyEnv service token with read access
Quick Sync
export KEYENV_TOKEN=your-service-token
# Export and bulk upload secrets
keyenv export -p YOUR_PROJECT_ID -e production --format json | \
jq '[.secrets[] | {name: .key, text: .value, type: "secret_text"}]' | \
wrangler secret:bulkSync Script
Create a reusable sync script:
#!/bin/bash
# sync-to-cloudflare.sh
set -euo pipefail
: "${KEYENV_TOKEN:?KEYENV_TOKEN is required}"
PROJECT_ID="${KEYENV_PROJECT:-YOUR_PROJECT_ID}"
ENVIRONMENT="${KEYENV_ENV:-production}"
echo "Syncing KeyEnv ($ENVIRONMENT) to Cloudflare Workers..."
# Export and transform for Cloudflare
keyenv export -p "$PROJECT_ID" -e "$ENVIRONMENT" --format json | \
jq '[.secrets[] | {name: .key, text: .value, type: "secret_text"}]' | \
wrangler secret:bulk
echo "Secrets synced to Cloudflare Workers!"CI/CD Integration
GitHub Actions
name: Deploy Worker
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install KeyEnv CLI
run: curl -fsSL https://keyenv.dev/install.sh | bash
- name: Sync secrets
run: |
export PATH="$HOME/.keyenv/bin:$PATH"
keyenv export -p ${{ vars.KEYENV_PROJECT }} -e production --format json | \
jq '[.secrets[] | {name: .key, text: .value, type: "secret_text"}]' | \
npx wrangler secret:bulk
env:
KEYENV_TOKEN: ${{ secrets.KEYENV_TOKEN }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
- name: Deploy Worker
run: npx wrangler deploy
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}Single Secret Sync
Sync individual secrets:
# Get a specific secret
value=$(keyenv get -p YOUR_PROJECT_ID -e production DATABASE_URL)
# Set in Cloudflare
echo "$value" | wrangler secret put DATABASE_URLMultiple Workers
Sync to multiple Workers:
#!/bin/bash
WORKERS=("api-worker" "auth-worker" "queue-worker")
for worker in "${WORKERS[@]}"; do
echo "Syncing to $worker..."
keyenv export -p YOUR_PROJECT_ID -e production --format json | \
jq '[.secrets[] | {name: .key, text: .value, type: "secret_text"}]' | \
wrangler secret:bulk --name "$worker"
doneSelective Sync
Sync only specific secrets:
# Only sync secrets that don't contain "LOCAL" in the key
keyenv export -p YOUR_PROJECT_ID -e production --format json | \
jq '[.secrets[] | select(.key | contains("LOCAL") | not) | {name: .key, text: .value, type: "secret_text"}]' | \
wrangler secret:bulkwrangler.toml Configuration
Non-sensitive config goes in wrangler.toml:
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"
[vars]
ENVIRONMENT = "production"
LOG_LEVEL = "info"
PUBLIC_API_URL = "https://api.example.com"
# Secrets are managed via wrangler secret (synced from KeyEnv)
# DATABASE_URL, API_KEY, etc.Using Secrets in Workers
Access secrets in your Worker code:
// src/index.ts
export interface Env {
DATABASE_URL: string;
API_KEY: string;
ENVIRONMENT: string; // From wrangler.toml [vars]
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Access secrets
const dbUrl = env.DATABASE_URL;
const apiKey = env.API_KEY;
return new Response('OK');
},
};Durable Objects
Secrets are available to Durable Objects too:
export class MyDurableObject {
constructor(private state: DurableObjectState, private env: Env) {}
async fetch(request: Request): Promise<Response> {
// Access secrets via this.env
const apiKey = this.env.API_KEY;
return new Response('OK');
}
}Workers KV
For frequently accessed secrets, consider caching in KV:
async function getSecret(env: Env, key: string): Promise<string | null> {
// Try KV cache first
let value = await env.SECRETS_KV.get(key);
if (!value) {
// Fall back to env binding
value = env[key as keyof Env] as string;
// Cache for 1 hour
await env.SECRETS_KV.put(key, value, { expirationTtl: 3600 });
}
return value;
}List Current Secrets
View secrets currently set in your Worker:
wrangler secret listDelete Secrets
Remove a secret:
wrangler secret delete SECRET_NAMERemove all and re-sync:
# List and delete all
for secret in $(wrangler secret list | tail -n +3 | awk '{print $1}'); do
wrangler secret delete "$secret" --force
done
# Re-sync from KeyEnv
keyenv export -p YOUR_PROJECT_ID -e production --format json | \
jq '[.secrets[] | {name: .key, text: .value, type: "secret_text"}]' | \
wrangler secret:bulkPages Functions
For Cloudflare Pages with Functions, set secrets via the dashboard or API:
# Using Pages API
secrets=$(keyenv export -p YOUR_PROJECT_ID -e production --format json)
echo "$secrets" | jq -r '.secrets[] | "\(.key)=\(.value)"' | while IFS='=' read -r key value; do
curl -X PATCH "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/pages/projects/$PROJECT_NAME" \
-H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"deployment_configs\":{\"production\":{\"env_vars\":{\"$key\":{\"value\":\"$value\",\"type\":\"secret_text\"}}}}}"
doneBest Practices
- Use wrangler.toml for non-secrets - Version control public config
- Automate syncing - Run sync in CI/CD before deployments
- Use secret bindings - Access via
env.SECRET_NAME, notprocess.env - Separate by environment - Use different Workers for staging/production
Troubleshooting
Wrangler Not Logged In
wrangler login
# or use API token
export CLOUDFLARE_API_TOKEN=your-tokenSecret Not Available
Ensure you've deployed after adding secrets:
wrangler deployType Errors
Update your Env interface to include all secrets:
export interface Env {
// Add all your secrets here
DATABASE_URL: string;
API_KEY: string;
}