Environment Management Guide for Multi-Worker Microservices
Best Practices for Cloudflare Workers & Pages Architecture
Goal: Zero Duck Hunting
This guide eliminates confusion about environments, deployments, and service bindings across multiple workers.
Table of Contents
- Environment Strategy
- Naming Conventions
- Service Binding Configuration
- Deployment Workflows
- Environment Variables
- Custom Domains
- Troubleshooting
- Quick Reference
Environment Strategy
Three-Tier Architecture
Local Development → Preview/Staging → Production| Environment | Purpose | Branch | Domain Pattern |
|---|---|---|---|
| Local | Development & Testing | main (local) | localhost:8787 |
| Preview/Staging | Integration Testing | main (preview) | preview.stratiqx.ai |
| Production | Live System | main (production) | stratiqx.ai, auth.stratiqx.ai |
Naming Conventions
Worker Service Names
Format: {service-name}-{environment}
✅ CORRECT:
- stratiqx-identity-server-dev
- stratiqx-identity-server-prod
- stratiqx-payment-dev
- stratiqx-payment-prod
- stratiqx-communication-dev
- stratiqx-communication-prod
❌ INCORRECT:
- stratiqx-identity-server (ambiguous)
- identity-prod (inconsistent prefix)
- payment-service-production (too verbose)Pages Project Names
Format: {project-name}
✅ CORRECT:
- strategic-intelligence-onboarding
- strategic-intelligence-dashboard
❌ INCORRECT:
- strategic-intelligence-onboarding-prod (redundant)Custom Domains
Pattern: {subdomain}.stratiqx.ai
✅ PRODUCTION:
- auth.stratiqx.ai → stratiqx-identity-server-prod
- payments.stratiqx.ai → stratiqx-payment-prod
- api.stratiqx.ai → stratiqx-communication-prod
✅ PREVIEW/STAGING:
- preview.stratiqx.ai → Pages Preview Environment
- dev-auth.stratiqx.ai → stratiqx-identity-server-dev
- dev-payments.stratiqx.ai → stratiqx-payment-devService Binding Configuration
Standard wrangler.toml Pattern
toml
name = "your-service-name"
compatibility_date = "2024-01-01"
# TOP-LEVEL = PRODUCTION DEFAULTS
# Always configure top-level bindings for production
[[services]]
binding = "AUTH_SERVICE"
service = "stratiqx-identity-server-prod"
[[services]]
binding = "PAYMENT_SERVICE"
service = "stratiqx-payment-prod"
[[services]]
binding = "COMMUNICATION_SERVICE"
service = "stratiqx-communication-prod"
[vars]
NODE_ENV = "production"
# PREVIEW ENVIRONMENT
[env.preview]
name = "your-service-name-preview"
[[env.preview.services]]
binding = "AUTH_SERVICE"
service = "stratiqx-identity-server-dev" # Use dev services for testing
[[env.preview.services]]
binding = "PAYMENT_SERVICE"
service = "stratiqx-payment-dev"
[[env.preview.services]]
binding = "COMMUNICATION_SERVICE"
service = "stratiqx-communication-dev"
[env.preview.vars]
NODE_ENV = "preview"
# PRODUCTION ENVIRONMENT (explicit)
[env.production]
name = "your-service-name"
[[env.production.services]]
binding = "AUTH_SERVICE"
service = "stratiqx-identity-server-prod"
[[env.production.services]]
binding = "PAYMENT_SERVICE"
service = "stratiqx-payment-prod"
[[env.production.services]]
binding = "COMMUNICATION_SERVICE"
service = "stratiqx-communication-prod"
[env.production.vars]
NODE_ENV = "production"Pages Function Service Binding Proxy
Create functions/api/{service}/[[path]].ts for each service:
typescript
// functions/api/payment/[[path]].ts
export async function onRequest(context: any) {
const { request, env } = context;
const url = new URL(request.url);
const servicePath = url.pathname.replace('/api/payment', '');
// Create service request
const serviceRequest = new Request(
`https://internal${servicePath}${url.search}`,
{
method: request.method,
headers: request.headers,
body: request.body,
}
);
// Use service binding if available, fallback to HTTP
if (env.PAYMENT_SERVICE) {
console.log('Using PAYMENT_SERVICE binding for:', servicePath);
return await env.PAYMENT_SERVICE.fetch(serviceRequest);
} else {
console.log('PAYMENT_SERVICE binding not available - using HTTP fallback');
const fallbackUrl = `https://payments.stratiqx.ai${servicePath}${url.search}`;
return await fetch(fallbackUrl, {
method: request.method,
headers: request.headers,
body: request.body,
});
}
}Deployment Workflows
Understanding Pages Deployments
| Deployment Command | Environment | Branch | Use Case |
|---|---|---|---|
wrangler pages deploy | Production | main | Live releases |
wrangler pages deploy --branch feature | Preview | feature | Feature testing |
wrangler pages deploy --branch main | Preview | main | Staging testing |
Deployment Checklist
For Workers:
bash
# 1. Deploy to development environment
wrangler deploy --env preview
# 2. Test in preview environment
# Run integration tests, verify service bindings
# 3. Deploy to production environment
wrangler deploy --env production
# 4. Verify production deployment
wrangler tail --env productionFor Pages:
bash
# 1. Deploy to preview for testing
wrangler pages deploy --branch staging
# 2. Test preview deployment
# Verify all service integrations work
# 3. Deploy to production (main branch)
wrangler pages deploy
# 4. Verify production custom domain
curl https://preview.stratiqx.ai/healthEnvironment Variables
Frontend (.env patterns)
.env.local (Development)
bash
VITE_NODE_ENV=development
VITE_IDENTITY_API_URL=http://127.0.0.1:8787
# Leave VITE_PAYMENT_API_URL unset to use service bindings.env.production (Production)
bash
VITE_NODE_ENV=production
VITE_IDENTITY_API_URL=https://auth.stratiqx.ai
# Leave VITE_PAYMENT_API_URL unset to force service bindings
VITE_STRIPE_PUBLISHABLE_KEY=pk_live_...Service Configuration Logic
typescript
// Frontend service configuration
constructor() {
const paymentApiUrl = import.meta.env.VITE_PAYMENT_API_URL;
if (!paymentApiUrl || paymentApiUrl === '') {
// Force service bindings when no external URL specified
this.baseURL = '/api/payment';
console.log('Using service bindings via /api/payment');
} else {
// Use external URL (for local development)
this.baseURL = paymentApiUrl;
console.log('Using external API:', paymentApiUrl);
}
}Custom Domains
Domain Mapping Strategy
Production Services:
├── auth.stratiqx.ai → stratiqx-identity-server-prod
├── payments.stratiqx.ai → stratiqx-payment-prod
├── api.stratiqx.ai → stratiqx-communication-prod
└── preview.stratiqx.ai → Pages Production Environment
Development/Staging:
├── dev-auth.stratiqx.ai → stratiqx-identity-server-dev
├── dev-payments.stratiqx.ai → stratiqx-payment-dev
└── dev-api.stratiqx.ai → stratiqx-communication-devDomain Configuration Commands
bash
# Add custom domain to worker
wrangler custom-domains add auth.stratiqx.ai
# Add custom domain to pages
wrangler pages domain add preview.stratiqx.aiTroubleshooting
Common Issues & Solutions
Issue: "Service binding not found"
Symptoms: HTTP calls instead of service bindings Solution:
- Check
wrangler.tomlservice names match exactly - Verify environment deployment (preview vs production)
- Ensure Pages Function proxy exists
Issue: "Environment mismatch"
Symptoms: Production showing as Preview Solution:
- Deploy to
mainbranch without--branchflag - Check Cloudflare dashboard environment settings
- Verify
wrangler.tomlenvironment configuration
Issue: "CORS errors in development"
Symptoms: Frontend can't reach local workers Solution:
- Add CORS headers to workers
- Use
wrangler dev --local --port 8787 - Set
VITE_*_API_URLfor local development
Issue: "Custom domain not working"
Symptoms: Domain shows 404 or old deployment Solution:
- Check DNS propagation:
dig preview.stratiqx.ai - Verify domain is added to correct service
- Wait for SSL certificate provisioning (up to 24h)
Debug Commands
bash
# Check deployment status
wrangler pages deployment list
# View environment variables
wrangler pages secret list
# Monitor worker logs
wrangler tail --env production --format pretty
# Check service binding status
wrangler dev --local --inspectQuick Reference
Service Naming Quick Check
bash
# Current StratIQX Services:
✅ stratiqx-identity-server-dev
✅ stratiqx-identity-server-prod
✅ stratiqx-payment-dev
✅ stratiqx-payment-prod
✅ stratiqx-communication-dev
✅ stratiqx-communication-prod
# Pages Projects:
✅ strategic-intelligence-onboardingEnvironment Variables Checklist
- [ ]
.env.productionhas noVITE_PAYMENT_API_URL(forces service bindings) - [ ]
wrangler.tomltop-level uses-prodservices - [ ]
env.previewuses-devservices for testing - [ ] All service binding names are consistent
Deployment Checklist
- [ ] Workers deployed to both
--env previewand--env production - [ ] Pages deployed to both preview (with
--branch) and production (without) - [ ] Custom domains point to correct services
- [ ] Service bindings tested in both environments
Success Metrics
When properly configured, you should see:
In Browser Network Tab:
✅ /api/payment/confirm-payment (service binding)
✅ /api/auth/validate (service binding)
❌ https://payments.stratiqx.ai/* (external HTTP - avoid this)In Worker Logs:
✅ "Using SERVICE_NAME binding for: /endpoint"
❌ "SERVICE_NAME binding not available - using HTTP fallback"In Frontend Console:
✅ "Using service bindings via /api/payment"
❌ "Using external API: https://payments.stratiqx.ai"Emergency Recovery
If environments get mixed up:
Immediate Fix:
bash# Force correct service bindings wrangler pages deploy --compatibility-date 2024-01-01Full Reset:
bash# Redeploy all services cd stratiqx-identity-server && wrangler deploy --env production cd stratiqx-payment && wrangler deploy --env production cd stratiqx-communication && wrangler deploy --env production cd strategic-intelligence-onboarding && wrangler pages deployVerify Recovery:
bashcurl https://preview.stratiqx.ai/health wrangler pages deployment list | head -5
Remember: When in doubt, check the service binding logs first!
Last updated: August 26, 2025