This site is not affiliated with or endorsed by Cloudflare, Inc. It simply showcases experiments built using Cloudflare services.
Cloudflare Experiments

Philosophy

Design principles and goals behind Cloudflare Experiments

Cloudflare Experiments is built on the principle that developers learn best by studying reference implementations for Cloudflare products - not toy examples or generic utilities.

The Problem

Most Cloudflare tutorials show very simple examples:

  • "Hello World" workers
  • Basic KV counters
  • Simple fetch proxies

While these are great for getting started, they don't showcase the real power of the Cloudflare platform. Developers are left wondering:

"Okay, I can return 'Hello World' from the edge... but what can I actually build with this?"

The Solution

Cloudflare Experiments bridges this gap by providing a curated collection of reference implementations - small, deployable examples that show how to wire up specific Cloudflare products and services.

Every experiment in this repository is:

Small and Focused

Each experiment demonstrates one specific capability of the Cloudflare platform:

  • Workers AI → AI Website Summary, GitHub Repo Explainer
  • Browser Rendering → Screenshot API
  • HTMLRewriter → Website to API, Dependency Analyzer
  • Edge Networking → Is It Down, URL DNS Lookup
  • D1 + KV → Link Shortener
  • R2 → R2 Storage
  • Durable Objects → Durable Counter
  • Cron Triggers → Cron Heartbeat
  • Queues → Task Queue
  • Request Metadata → Where Am I, AI Bot Visibility

Single responsibility principle: One experiment, one capability. This makes the code easy to understand and the concept easy to grasp.

Independently Deployable

Every experiment is completely independent:

experiments/
├── ai-website-summary/     # Independent
│   ├── package.json
│   ├── wrangler.json
│   ├── src/
│   └── README.md
├── screenshot-api/         # Independent
│   ├── package.json
│   ├── wrangler.json
│   ├── src/
│   └── README.md
└── is-it-down/            # Independent
    ├── package.json
    ├── wrangler.json
    ├── src/
    └── README.md

No shared code between experiments. Each has its own:

  • Dependencies (package.json)
  • Configuration (wrangler.json)
  • Types and utilities
  • Deploy button

You can:

  • Clone just one experiment
  • Deploy just one experiment
  • Fork just one experiment
  • Modify one without touching others

This is intentional. While shared code might reduce duplication, it creates coupling that makes experiments harder to understand and reuse independently.

Easy to Understand

Every experiment follows the same structure:

// src/index.ts - Always the entry point
import { Hono } from "hono";
import type { Env } from "./types/env";
import whereamiRoutes from "./routes/whereami";

const app = new Hono<{ Bindings: Env }>();

app.route("/", whereamiRoutes);

// Always include a GET / for experiment info
app.get("/", (c) => {
  return c.json({
    name: "whereami",
    description: "Request metadata from Cloudflare's edge (request.cf)",
    usage: "GET /whereami",
  });
});

// Always include global error handling
app.onError((err, c) => {
  return c.json({ error: err.message, code: "INTERNAL_ERROR" }, 500);
});

export default {
  fetch: app.fetch,
};

Consistent patterns:

  • Use Hono for routing (fast, type-safe, Workers-optimized)
  • Use TypeScript with strict typing
  • Use shared error/success helpers (jsonError, jsonSuccess)
  • Validate inputs (especially URLs) with clear error codes
  • Include comprehensive error handling

Designed to Run Fast

Goal: Under 60 seconds from clicking "Deploy" to having a working API.

This means:

  • Stateless first: Most experiments use edge compute and fetch-no persistent storage required
  • No complex setup: Works with default Cloudflare settings where possible
  • Minimal dependencies: Each experiment installs only what it needs
  • Edge-optimized: Run close to users with sub-100ms response times

Example: The "Is It Down" experiment:

  1. Click Deploy button
  2. Authenticate with Cloudflare
  3. Worker is live in ~30 seconds
  4. Test: curl "https://your-worker.workers.dev/check?url=https://example.com"

No database setup. No API keys. No configuration files.

Click-to-Deploy Ready

Every experiment includes a Deploy to Cloudflare Workers button:

[![Deploy to Cloudflare Workers](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/shrinathsnayak/cloudflare-experiments/tree/main/apps/experiments/is-it-down)

This lowers the barrier to experimentation. You can:

  • Try before you clone
  • Deploy to production in one click
  • Fork and modify the deploy URL to use your own repo

Design Principles

1. Product Reference, Not Generic Utilities

Every experiment maps to a specific Cloudflare product or binding:

Durable Counter

Reference pattern: globally consistent state with Durable Objects

Task Queue

Reference pattern: async processing with Queues producer/consumer

Link Shortener

Reference pattern: D1 primary storage with KV read cache

Screenshot API

Reference pattern: headless browser automation with Browser Rendering

These are starting points you can copy when building on Cloudflare - not standalone utilities that happen to run on Workers.

2. Edge-First Architecture

Cloudflare's edge network spans 300+ cities. Experiments demonstrate how to leverage this:

Example: Is It Down

Instead of checking from a single server location:

// Traditional approach (single server)
const response = await fetch(url);
return response.ok ? "up" : "down";

Check from the edge closest to the user:

// Edge approach (Cloudflare)
const cf = c.req.raw.cf;
const result = await fetchWithTiming(url);
return {
  status: result.ok ? "reachable" : "unreachable",
  responseTime: result.responseTimeMs,
  colo: cf?.colo, // Which edge location served this
};

The user in London gets results from LHR (London Heathrow), the user in Tokyo gets results from NRT (Narita). Global performance by default.

3. Platform Capabilities Over Abstractions

Experiments showcase native Cloudflare features:

Workers AI (not external AI APIs):

// experiments/ai-website-summary/src/lib/ai.ts
const ai = c.env.AI;
const response = await ai.run("@cf/meta/llama-2-7b-chat-int8", {
  messages: [
    {
      role: "user",
      content: `Summarize this webpage: ${text}`,
    },
  ],
});

Browser Rendering (not external screenshot services):

// experiments/screenshot-api/src/lib/screenshot.ts
const browser = await puppeteer.launch(c.env.BROWSER);
const page = await browser.newPage();
await page.goto(url);
const screenshot = await page.screenshot();

HTMLRewriter (not external parsing services):

// experiments/website-to-api/src/lib/parser.ts
new HTMLRewriter()
  .on("h1", {
    element(element) {
      headings.push(element.getAttribute("textContent"));
    },
  })
  .transform(response);

Every experiment teaches you what Cloudflare can do natively without external dependencies.

4. Consistent Code Standards

All experiments follow the same conventions:

Error Handling:

// src/utils/response.ts (duplicated in each experiment)
export function jsonError(c: Context, message: string, code: string, status = 400) {
  return c.json({ error: message, code }, status);
}

export function jsonSuccess(c: Context, data: unknown) {
  return c.json(data);
}

URL Validation:

// src/lib/url.ts (duplicated in each experiment)
export function validateUrl(input: string | undefined): string | null {
  if (!input) return null;
  try {
    const url = new URL(input);
    if (url.protocol !== "http:" && url.protocol !== "https:") {
      return null;
    }
    return url.href;
  } catch {
    return null;
  }
}

Error Codes:

  • INVALID_URL - Bad or missing URL parameter
  • FETCH_ERROR - Failed to fetch external resource
  • INTERNAL_ERROR - Uncaught exception
  • NOT_FOUND - Resource doesn't exist

Consistent patterns make the codebase predictable and easy to navigate.

5. TypeScript All the Way

Every experiment uses strict TypeScript:

// src/types/env.d.ts
export interface Env {
  AI?: Ai; // Workers AI binding
  BROWSER?: Fetcher; // Browser Rendering binding
  DB?: D1Database; // D1 binding
  LINKS_CACHE?: KVNamespace; // KV binding
}
// src/types/check.ts
export type CheckResponse =
  | {
      status: "reachable";
      responseTime: number;
      statusCode: number;
      colo?: string;
    }
  | {
      status: "unreachable";
      responseTime: number;
      statusCode?: number;
      colo?: string;
      error?: string;
    };

Full type safety from request to response.

What This Means for You

As a Learner

You can:

  • Learn by example: See real implementations of Cloudflare features
  • Copy and modify: Each experiment is a starting point for your own projects
  • Understand the platform: See what's possible with Workers, AI, D1, KV, etc.

As a Builder

You can:

  • Deploy immediately: Click-to-deploy to production
  • Fork and customize: Each experiment is MIT licensed
  • Build on top: Use experiments as building blocks for larger applications

As a Contributor

You can:

  • Add new experiments: Showcase other Cloudflare capabilities (Vectorize, Images, Email Workers)
  • Improve existing ones: Better error handling, new features, performance optimizations
  • Fix bugs: Help make the examples more robust

See CONTRIBUTING.md for guidelines.

Future Directions

The collection will continue to grow with experiments demonstrating:

  • Vectorize - Vector search at the edge
  • Images API - On-the-fly image transformation
  • Email Workers - Process incoming email
  • Hyperdrive - Accelerate database queries
  • Workers Analytics Engine - Event logging and analytics

Each new experiment will follow the same principles: real tools, independently deployable, easy to understand, and edge-first.

Why It Matters

Cloudflare's edge platform is incredibly powerful, but the learning curve can be steep. Cloudflare Experiments makes it tangible:

  • See concrete examples of what you can build
  • Deploy real tools in under 60 seconds
  • Learn platform capabilities through working code
  • Build production patterns from day one

The goal is simple: help developers discover what's possible on the Cloudflare edge by showing them reference implementations they can deploy, read, and adapt.

The best way to learn is to deploy an experiment, look at the code, and modify it. Start with something simple like Where Am I, then move to more complex experiments like Link Shortener.

Get Involved

On this page