Library · Connections: APIs, MCP and running 24/7

Deploying 24/7: how to put your project online with Cloudflare Workers, GitHub and Vercel

Builder75 minUpdated: October 2026
27 of 105 in the library

Module: 5, Technical tools | Time: about 30 min theory + 45 min practice


The gist

Picture this: you've built a mechanical mail carrier that works great at your house. Now you need to send it off to work on its own, at an office where it shows up every day at 9 a.m. whether you're there or not. Deployment is exactly that: moving your automation from "works on my computer" to "works all the time, in the cloud, without me."


Key concepts

  • The difference between running something locally and deploying it to the cloud
  • Cloudflare Workers as an edge platform (computing on the servers closest to the user) for 24/7 automations
  • Deployments are deterministic: the code runs exactly as written, with no self-correction
  • Rate limiting (caps on how often you can make requests) and quotas for API keys (API: application programming interface, the way programs talk to each other) in production
  • Vercel for deploying web apps
  • Alternatives: Trigger.dev, Modal, Railway (comparison)

Theory

What changes when you deploy

When you're building a workflow with Claude Code, the agent (an autonomous program that carries out tasks) can fix a mistake right in the middle of the work. Wrote the wrong file path? The agent notices, fixes it, and keeps going. This is called adaptive execution.

A deployment doesn't have that. You deploy code and tools, not the agent itself with its ability to reason and correct. The code runs deterministically: step 1 → step 2 → step 3. If something goes wrong at step 2, you get an error. No "hang on, let me rethink this."

🎨 Picture this: building with Claude is like a rehearsal with the director sitting next to you. You make a mistake, the director corrects you, you keep going. A deployment is the live show with no director in the house. You flub the third act, the show falls apart, curtain.

Takeaway: all your testing has to happen during development, not in the hope that "production will sort it out."


Cloudflare Workers: your automation factory on the edge

🎨 Picture this: Cloudflare Workers is a factory that never sleeps. You go home at 6 p.m. and the assembly line keeps running: collecting data, sending reports, writing to the database. You're gone, production goes on.

Cloudflare Workers are edge functions that run on Cloudflare's servers in hundreds of cities around the world. They're not a separate SaaS platform (software as a service) but part of Cloudflare's infrastructure.

What Workers can do:

  • Cron Triggers (scheduling with cron, a task scheduler): every Monday at 08:00, the first of every month, every 15 minutes
  • HTTP webhooks (a webhook is an HTTP notification): a request comes in → the Worker runs its logic
  • KV Storage (key-value storage): keep data between runs (state, results, cache)
  • Messenger integration: send results straight to a chat bot. The examples below use a Telegram bot; Slack or email work the same way

Why Cloudflare Workers and not Trigger.dev?

Cloudflare Workers Trigger.dev
Free tier 100,000 requests/day There's a free plan; see the pricing page for details
Paid from $5/mo (10 million requests included, then $0.30 per million) Paid plans; see the pricing page
Edge Hundreds of cities worldwide Jobs run on the service's servers, not on the edge
Storage KV (built in, with a free allowance) Needs an external database
Monitoring wrangler tail + logs Dashboard (a nice one)
GitHub GitHub Actions or wrangler deploy Native integration
Execution limit CPU limit: 10 ms (free); longer limits for cron on paid plans, see the Cloudflare limits page No limit on duration

Cloudflare prices and limits in the table are as of October 2026. Current prices and versions: What's current.

When Trigger.dev is better: if a task computes or processes data for longer than the Workers CPU limits allow (heavy scraping, video processing). For most lightweight automations, Workers are cheaper and faster.

Trigger.dev is a good tool. We use Workers because at small scale they cost less and they're built into an ecosystem we already use. Compare using your own numbers.


The deployment process: 5 steps

Step 1: Create a Worker project

bash
npm create cloudflare@latest -- my-automation
cd my-automation

The tool asks a few questions: choose "Hello World example," "Worker only," and TypeScript as the language. It creates a project structure with wrangler.jsonc (the config; in older projects it's wrangler.toml, and the toml format is still supported) and src/index.ts (the code). Below, the config is shown in toml format; the settings mean the same thing either way.

Step 2: Set up secrets

Secrets are added through the CLI (command-line interface), not in files:

bash
wrangler secret put ANTHROPIC_API_KEY
# You type the key in the terminal; it's encrypted and stored in Cloudflare
wrangler secret put TELEGRAM_BOT_TOKEN

🎨 Picture this: secrets in wrangler secret put are like a bank safe deposit box. The key exists, but it's not in your pocket, it's in secure storage. Nobody can pull it out of your git repository (git is a version control system) or your project folder.

Never store keys in code. Only through wrangler secret put.

Step 3: Set the schedule in wrangler.toml

toml
name = "weekly-job-scraper"
main = "src/index.ts"
compatibility_date = "2026-10-01"  # use today's date

[triggers]
crons = ["0 9 * * 1"]  # every Monday at 09:00 UTC

[[kv_namespaces]]
binding = "CACHE"
id = "your-kv-namespace-id"

Step 4: Write the Worker

typescript
export default {
  async scheduled(event, env, ctx) {
    // 1. Read the previous state from KV
    const lastRun = await env.CACHE.get("last-run");
    
    // 2. Call the Anthropic API
    const response = await fetch("https://api.anthropic.com/v1/messages", {
      method: "POST",
      headers: {
        "x-api-key": env.ANTHROPIC_API_KEY,
        "content-type": "application/json",
        "anthropic-version": "2023-06-01"
      },
      body: JSON.stringify({
        model: "claude-sonnet-5-5",  // check the current model ID on the What's current page
        max_tokens: 1024,
        messages: [{ role: "user", content: "Generate a digest..." }]
      })
    });
    const data = await response.json();
    const result = data.content.map((b) => (b.type === "text" ? b.text : "")).join("");
    
    // 3. Send it to Telegram
    await fetch(`https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage`, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        chat_id: env.TELEGRAM_CHAT_ID,
        text: result,
        parse_mode: "Markdown"
      })
    });
    
    // 4. Save the state
    await env.CACHE.put("last-run", new Date().toISOString());
  }
};

Step 5: Deploy and monitor

bash
# Deploy
wrangler deploy

# Real-time monitoring
wrangler tail

You test a cron run locally: start npx wrangler dev --test-scheduled, and in another terminal window run:

bash
curl "http://localhost:8787/cdn-cgi/local/scheduled"

The Cloudflare Dashboard shows logs for every run, errors and metrics.


A real example: a weekly job listings digest

The task: every Friday, collect job listings and send a digest to a chat bot.

Type this into the chat
Worker architecture:
1. Cron Trigger: "0 17 * * 5" (Friday 17:00 UTC)
2. Read previous results from KV (for deduplication)
3. Fetch data from 5 job listing APIs
4. Call the Anthropic API to structure + analyze
5. Deduplicate (remove repeats from last week)
6. Save the new results to KV
7. Send the digest to Telegram
8. Record metrics (tokens, the smallest unit of text for AI; cost) in an audit KV

An important limit: CPU time. On the Free tier you get 10 ms of CPU per run; on the Paid plan (from $5/mo) cron jobs get a much longer limit, which depends on how often the job runs (see Cloudflare's limits page). Waiting on the network (API calls, KV reads) doesn't count toward CPU time, so for most API workflows this is enough. For heavy scraping with Playwright, you need Trigger.dev or a separate server.


Rate limiting: the invisible wall

In production you're dealing with real API limits:

Anthropic:

  • Limits on requests and tokens per minute depend on your account's tier and on the model; check the exact values in the Claude Console and in the Rate limits section of the documentation
  • New accounts start at a low tier, and limits grow as you use the service

🎨 Picture this: a rate limit is the checkout line at a store. If you run up with new items too fast, the cashier says "hold on." Without retry logic, you turn around and leave. With retry logic, you wait a second and try again.

If you go over the limit: the API returns a 429 error. Without retry logic, the workflow crashes.

The fix: add delays between requests and use retries with exponential backoff:

typescript
async function callWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (e) {
      if (e.status === 429 && i < maxRetries - 1) {
        await new Promise(r => setTimeout(r, 1000 * Math.pow(2, i)));
        continue;
      }
      throw e;
    }
  }
}

Quota planning: if a workflow processes 500 documents a day, figure out how many tokens that will use. Don't go over your daily quotas.


Vercel: for web apps

Cloudflare Workers are for automations and background jobs. Vercel is for web apps and APIs:

  • Deploying Next.js / React apps
  • Serverless functions (no server to manage): REST API endpoints
  • Edge Functions: run close to the user
  • Free Hobby plan: fine for personal prototypes, but only for non-commercial projects. Commercial projects need the paid Pro plan ($20 a month per developer, as of October 2026)

A typical setup:

Code
Vercel (web interface) ←→ Cloudflare Workers (background jobs) ←→ KV Storage
                                      ↓
                              Telegram bot (notifications)

A user clicks a button on the site → Vercel receives the request → a Cloudflare Worker runs the job → the result goes to KV + a chat notification.

A separate note on static sites: for them and for full-stack apps, Cloudflare now recommends Workers with static files (Workers Static Assets). Pages keeps working, but new features are showing up in Workers (as of October 2026).


Cloudflare Workers: plans

Setting Free Paid (from $5/mo)
Requests 100,000/day no limit (10 million/mo included, then $0.30 per million)
CPU time per request 10 ms longer; see the limits page
KV reads daily allowance; see the pricing page monthly allowance included; see the pricing page
KV writes daily allowance; see the pricing page monthly allowance included; see the pricing page
Cron Triggers per account limited; see the limits page more; see the limits page
Workers limited; see the limits page more; see the limits page

To get started: the Free tier is enough for 1-3 automations. Paid (from $5/mo) is for serious use. Numbers are as of October 2026.

Current prices: Cloudflare Workers Pricing


Comparing deployment platforms

Platform What it's for Price (as of October 2026) Execution limit Our pick?
Cloudflare Workers Cron + API automations from $5/mo, free plan available CPU: 10 ms (free) / longer for cron (paid) ✅ Primary
Trigger.dev Heavy, long-running jobs Free plan and paid plans, see the pricing page No limit on duration Alternative
Vercel Web apps + APIs Hobby free (non-commercial only), Pro $20/mo Depends on plan, see the docs For the UI
Modal ML + GPU jobs Pay-per-use, see the pricing page See the docs For AI-heavy work
Railway A full server See the pricing page See the docs If you need a VPS (virtual private server)
Render Web services + cron jobs See the pricing page See the docs Simple deploys

Common deployment mistakes

  1. Forgetting to set secrets with wrangler secret put. The most common mistake: you copied the code, deployed it, and the Worker crashes with "undefined" because the API keys aren't set. Always check wrangler secret list before deploying.

  2. Not testing locally before deploying. wrangler dev runs the Worker locally, so use it. One run through wrangler dev saves an hour of debugging in production.

  3. Storing secrets in wrangler.toml. The wrangler.toml file often ends up in git. Secrets (API keys, tokens) go only through wrangler secret put, never in wrangler.toml or in code.

  4. Ignoring the CPU time limit. Free tier = 10 ms of CPU time. Network waiting doesn't count, but parsing large responses and complex logic can easily blow past it. Use wrangler tail to check how much CPU time the Worker uses.

  5. Forgetting retries on 429 errors. In production, API services return 429 (rate limit) regularly. Without retry logic the Worker will simply crash at 3 a.m., and you'll find out in the morning.


A real wrangler.toml: Worker configuration

toml
name = "my-weekly-digest"
main = "src/index.ts"
compatibility_date = "2026-10-01"   # use today's date

# Schedule: every Monday at 09:00 UTC
[triggers]
crons = ["0 9 * * 1"]

# KV storage for state between runs
[[kv_namespaces]]
binding = "CACHE"
id = "abc123def456"        # ID from `wrangler kv namespace create CACHE`
preview_id = "xyz789"      # for wrangler dev

# Environment variables (NOT secrets, fine to keep in the config)
[vars]
TELEGRAM_CHAT_ID = "123456789"
ENVIRONMENT = "production"

# Secrets are added through the CLI:
# wrangler secret put ANTHROPIC_API_KEY
# wrangler secret put TELEGRAM_BOT_TOKEN

Note: you get the KV namespace id from wrangler kv namespace create CACHE. Secrets (ANTHROPIC_API_KEY and so on) are set only through wrangler secret put.


Pre-deployment checklist

🎨 Picture this: deploying without a checklist is like launching a rocket without a preflight check. The rocket will take off, but whether it comes back is another question.

Before you deploy, be sure to check:


Practice

Exercise: deploy a simple automation to Cloudflare Workers

  1. Install Node.js (you need it for the commands below). Wrangler comes with the project, so you don't have to install it globally: use npx wrangler ...
  2. Create a project: npm create cloudflare@latest -- quote-bot (Hello World, Worker only, TypeScript)
  3. Log in: npx wrangler login
  4. Write a Worker: every 5 minutes, fetch a record from a public test API (for example jsonplaceholder.typicode.com) and log the result
  5. Set the cron in the Wrangler config: crons = ["*/5 * * * *"]
  6. Test locally: wrangler dev --test-scheduled
  7. Deploy: wrangler deploy
  8. Watch it run: wrangler tail
  9. Bonus: add a secret (wrangler secret put MY_SECRET) and use it in the Worker as env.MY_SECRET
  10. Bonus 2: create a KV namespace and save the number of the last record so you don't repeat yourself

Expected result: wrangler tail shows regular successful runs with logs of the records.


Tools and resources

  • Cloudflare Workers: edge platform for automations
  • Wrangler CLI: the CLI for creating, testing and deploying Workers
  • Cloudflare KV: key-value storage for state between runs
  • Cloudflare D1: an SQL database (SQLite) for Workers, if KV isn't enough
  • Cloudflare R2: file storage (similar to S3), with a free allowance (terms on the pricing page)
  • Cloudflare Workers Pricing: current plans
  • Vercel: deploying web apps; the free Hobby plan is for non-commercial projects only
  • Trigger.dev: an alternative for long-running jobs
  • Railway: a full server, if you need a VPS
  • Render: simple deploys of web services + cron jobs
  • GitHub Actions: an alternative for CI/CD (continuous integration and delivery) pipelines

Key takeaways

When you deploy, you're sending code, not the agent. Code doesn't fix itself, so test DURING development, not after.

Rate limiting is a real problem in production. Add delays and retry logic before something crashes at 3 a.m.

Cloudflare Workers = edge speed + KV storage + cron out of the box. At small scale they're noticeably cheaper than Trigger.dev. For most lightweight jobs, they're a good choice.



Next lesson

→ Multimodality: images, PDFs and audio in Claude's work

The mark stays in this browser only and is never sent anywhere. My progress