Cloudflare Workers × Antigravity Deployment Guide
In the era of edge computing, global-scale high-speed content delivery is a necessity. Cloudflare Workers provides a powerful platform to solve this challenge, and when combined with Antigravity Lab, it significantly enhances developer productivity and deployment efficiency.
Understanding Cloudflare Workers
Cloudflare Workers is a serverless computing platform that executes code on Cloudflare's global network. Unlike traditional centralized serverless architectures, your code runs at edge locations geographically closest to your users.
Benefits of Edge Computing
Reduced Latency With 280+ edge locations worldwide, average response times improve by 30-40% compared to centralized server models. Users experience near-instantaneous responses regardless of geographic location.
Automatic Scalability Traffic is naturally distributed to geographically proximate edges. Sudden traffic spikes don't require provisioning additional capacity—the infrastructure automatically scales.
Cost Efficiency Pay-per-use pricing based on execution duration and request count eliminates the need to over-provision for peak loads. This model favors unpredictable traffic patterns.
Built-in Security DDoS protection and WAF capabilities are natively integrated. Security is enforced at the edge before malicious traffic reaches origin servers.
Architecture Advantages
Workers executes within 50 milliseconds of 99% of internet users globally. This performance difference becomes particularly evident in user-facing metrics: faster page loads, reduced API latency, and improved perceived responsiveness.
Getting Started with Antigravity
Antigravity Lab's agent capabilities accelerate Cloudflare Workers project initialization and configuration optimization.
Step 1: Install Wrangler
npm install -g wrangler
wrangler loginWrangler is the official Cloudflare Workers CLI. The login command authenticates with your Cloudflare account and caches credentials.
Step 2: Create a New Project
wrangler generate my-workers-project
cd my-workers-projectThis creates a fully functional project scaffold. Using Antigravity Lab at this stage enables intelligent suggestions for project structure optimization based on your intended use case.
Step 3: Verify Project Structure
my-workers-project/
├── src/
│ └── index.ts # Main handler function
├── wrangler.toml # Configuration file
├── package.json
├── tsconfig.json
├── .gitignore
└── package-lock.json
Antigravity Lab's code analysis tools can inspect this structure and recommend optimizations for specific deployment targets.
Deploying Next.js with OpenNext Adapter
Next.js applications require the OpenNext adapter to execute on Cloudflare Workers. This adapter transpiles Next.js runtime to compatible Worker format.
Install OpenNext
npm install -D @opennextjs/cloudflareConfigure next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
platformLogs: {
edge: "debug",
nodeCompat: true,
},
},
headers() {
return [
{
source: "/api/:path*",
headers: [
{ key: "Cache-Control", value: "no-cache" },
],
},
];
},
};
module.exports = nextConfig;Complete wrangler.toml Configuration
name = "my-next-app"
type = "service-worker"
account_id = "your-account-id"
workers_dev = true
route = "example.com/*"
zone_id = "your-zone-id"
env = "production"
[env.production]
vars = { ENVIRONMENT = "production", LOG_LEVEL = "info" }
routes = [
{ pattern = "example.com/api/*", zone_name = "example.com" }
]
[build]
command = "npm run build"
cwd = "./"
main = "./.open-next/server/index.js"
[[migrations]]
tag = "v1"
new_sqlite_db = "app_database"
[[d1_databases]]
binding = "DB"
database_name = "production"
database_id = "uuid-here"
[[kv_namespaces]]
binding = "KV_CACHE"
id = "uuid-here"Build and Validate
npm run build
wrangler deploy --dry-runThe --dry-run flag validates configuration without actual deployment. Antigravity Lab automatically analyzes deployment logs to identify potential issues.
Comprehensive wrangler.toml Configuration
The wrangler.toml file is central to your Workers application. Understanding all available options enables optimal configuration for your workload.
Core Configuration
name = "my-workers-app"
main = "src/index.ts"
compatibility_date = "2026-03-01"
compatibility_flags = ["nodejs_compat"]The compatibility_date determines which feature set is active. Updating periodically ensures you benefit from latest optimizations and bug fixes from Cloudflare.
Database Integration
[[d1_databases]]
binding = "DB"
database_name = "production"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
migrations_dir = "src/migrations"Cloudflare D1 provides SQLite at the edge. This binding makes database accessible within your Worker function.
Key-Value Storage
[[kv_namespaces]]
binding = "KV_CACHE"
id = "cache-uuid"
preview_id = "cache-preview-uuid"
[[kv_namespaces]]
binding = "KV_SESSION"
id = "session-uuid"
preview_id = "session-preview-uuid"Multiple KV namespaces allow logical separation between caching, session management, and other data concerns.
Analytics Engine
[[analytics_engine_datasets]]
binding = "ANALYTICS"This enables collection of custom analytics events for monitoring application behavior and performance.
Environment Variables and Secrets Management
Proper secret management is critical for security and operational reliability in production environments.
Development Configuration
# .env.local
DATABASE_URL=postgresql://user:pass@localhost/db
API_SECRET=local-dev-key-xyz
FEATURE_FLAGS=beta,experimentalProduction Secrets
wrangler secret put DATABASE_URL
# Interactively enter: postgresql://prod-user:pass@prod.aws.com/db
wrangler secret put API_SECRET
# Interactively enter your production secret keySecrets are encrypted at rest in Cloudflare's systems and decrypted only within Worker execution contexts.
Accessing in Code
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const dbUrl = env.DATABASE_URL;
const apiSecret = env.API_SECRET;
// Use variables safely
const connection = await initDatabase(dbUrl);
const response = await processRequest(request, apiSecret);
return response;
},
};
interface Env {
DATABASE_URL: string;
API_SECRET: string;
DB: D1Database;
KV_CACHE: KVNamespace;
ANALYTICS: AnalyticsEngine;
}Environment-Specific Configuration
[env.staging]
vars = { API_ENDPOINT = "https://api.staging.example.com", DEBUG = "true" }
routes = [
{ pattern = "staging.example.com/*", zone_name = "example.com" }
]
[env.production]
vars = { API_ENDPOINT = "https://api.example.com", DEBUG = "false" }
routes = [
{ pattern = "example.com/*", zone_name = "example.com" }
]Deploy to different environments:
wrangler deploy --env staging
wrangler deploy --env productionCI/CD Pipeline: GitHub to Cloudflare Workers
Automated deployment removes manual steps and reduces human error. A proper CI/CD pipeline ensures consistent deployments across environments.
GitHub Actions Workflow
name: Deploy to Cloudflare Workers
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test-and-deploy:
runs-on: ubuntu-latest
permissions:
contents: read
deployments: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm run test
- name: Build application
run: npm run build
- name: Deploy to Cloudflare
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
environment: ${{ github.ref == 'refs/heads/main' && 'production' || 'staging' }}
secrets: |
DATABASE_URL
API_SECRETPreview Deployments for Pull Requests
- name: Deploy Preview
if: github.event_name == 'pull_request'
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
environment: preview
previewToken: trueThis enables preview URLs for PRs, allowing stakeholders to validate changes before merging to main.
Custom Domain Configuration
Serve your Workers application from custom domains rather than the default workers.dev subdomain.
DNS Configuration
Record Type: CNAME
Name: app.example.com
Target: example.com.cdn.cloudflare.net
TTL: Auto
Proxy: Proxied
If your domain uses Cloudflare nameservers, you can configure routing directly in the Cloudflare dashboard.
Route Definition in wrangler.toml
route = "app.example.com/*"
zone_id = "your-cloudflare-zone-id"All requests to app.example.com route through your Worker.
Multi-Subdomain and Path Routing
[[routes]]
pattern = "api.example.com/*"
zone_name = "example.com"
[[routes]]
pattern = "example.com/api/*"
zone_name = "example.com"
[[routes]]
pattern = "static.example.com/*"
zone_name = "example.com"This configuration handles API requests on dedicated subdomains, path-based routing, and asset serving from separate origins.
Performance Optimization Strategies
While edge execution provides baseline performance benefits, additional optimization techniques dramatically improve responsiveness.
Intelligent Caching Strategy
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Use Cache API for edge caching
const cacheKey = new Request(request.url, { method: "GET" });
const cache = caches.default;
let response = await cache.match(cacheKey);
if (!response) {
response = await fetch(request);
const headers = new Headers(response.headers);
headers.set("Cache-Control", "public, max-age=3600");
const cachedResponse = new Response(response.body, {
status: response.status,
statusText: response.statusText,
headers,
});
await cache.put(cacheKey, cachedResponse.clone());
}
return response;
},
};KV-Based Cache with TTL
const cachedData = await env.KV_CACHE.get(cacheKey);
if (cachedData) {
return new Response(cachedData, {
headers: {
"X-Cache": "HIT",
"Content-Type": "application/json",
},
});
}
const freshData = await fetch(upstreamUrl);
const body = await freshData.text();
await env.KV_CACHE.put(cacheKey, body, {
expirationTtl: 3600, // 1 hour TTL
});
return new Response(body, {
headers: {
"X-Cache": "MISS",
"Content-Type": "application/json",
},
});Response Compression
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const response = await fetch(request);
const contentType = response.headers.get("content-type");
if (contentType?.includes("application/json")) {
const text = await response.text();
const compressed = await compressGzip(text);
return new Response(compressed, {
headers: {
...Object.fromEntries(response.headers),
"Content-Encoding": "gzip",
"Content-Length": compressed.length.toString(),
},
});
}
return response;
},
};Query Optimization
// ❌ Inefficient: N+1 query problem
const users = await env.DB.prepare("SELECT id, name FROM users LIMIT 100").all();
for (const user of users.results as any[]) {
const posts = await env.DB.prepare(
"SELECT * FROM posts WHERE user_id = ?"
).bind(user.id).all();
// Process posts...
}
// ✅ Efficient: Single query with JOIN
const results = await env.DB.prepare(`
SELECT users.id, users.name, posts.id as post_id, posts.title
FROM users
LEFT JOIN posts ON users.id = posts.user_id
LIMIT 100
`).all();Bundle Size Analysis
npm install -D bundle-analyzer
npm run build -- --analyzeReview the bundle report and eliminate unnecessary dependencies:
{
"dependencies": {
"lodash": "remove-if-unused",
"moment": "consider-date-fns-alternative"
}
}