ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-03-10Intermediate

Cloudflare Workers × Antigravity Deployment Guide

Complete guide to deploying applications with Cloudflare Workers and Antigravity for edge computing

Cloudflare Workers7deployment7Next.js5edge2Wrangler

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 login

Wrangler 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-project

This 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/cloudflare

Configure 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-run

The --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,experimental

Production 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 key

Secrets 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 production

CI/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_SECRET

Preview 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: true

This 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 -- --analyze

Review the bundle report and eliminate unnecessary dependencies:

{
  "dependencies": {
    "lodash": "remove-if-unused",
    "moment": "consider-date-fns-alternative"
  }
}
Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

App Dev2026-06-13
Keeping TanStack Query v5 Cache Consistency Intact — Invalidation Boundaries, Optimistic Updates, and SSR Traps, Worked Through with Antigravity
A like that snaps back a moment after you tap it; a stale value that lingers when you return from another tab. This walks through the three places TanStack Query v5 cache consistency breaks, with working code for invalidation boundaries, onMutate rollback, and per-request QueryClient isolation.
App Dev2026-05-01
Deploying Apps with Antigravity to Railway — A Practical Middle Ground Between Cloudflare Workers and Vercel for Indie Developers
A hands-on guide to deploying from Antigravity to Railway. Covers when Cloudflare Workers and Vercel fall short, and how Railway fills that gap for long-running tasks and persistent connections.
App Dev2026-04-28
Build a Complete SaaS in Antigravity — Stripe Billing, Auth, and Deployment Without Leaving Your IDE
Build an entire SaaS product within Antigravity IDE — from Supabase auth to Stripe billing to Cloudflare Workers deployment, without switching tools.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →