First Worker

Scaffold a Hono-based Worker, run it locally, and deploy to Cloudflare’s edge. This is the starting point for the Webhook Hub project.

Prerequisites: Platform Model, Workers

Scaffold the Project

npm create cloudflare@latest webhook-hub -- --template=hono
cd webhook-hub

The scaffolder creates a working project with Hono, TypeScript, and a wrangler.jsonc config. You can deploy immediately or customize first.

Project Structure

webhook-hub/
├── src/
│   └── index.ts              # Hono app (your code)
├── worker-configuration.d.ts # Auto-generated binding types
├── wrangler.jsonc             # Cloudflare config
├── package.json
└── tsconfig.json

Understanding wrangler.jsonc

The generated config is minimal:

{
  "name": "webhook-hub",
  "main": "src/index.ts",
  "compatibility_date": "2025-01-01",
  "compatibility_flags": ["nodejs_compat"]
}

Key fields:

  • name - Worker name (also the default *.workers.dev subdomain)
  • main - entry point
  • compatibility_date - locks runtime behavior to a point in time (update periodically)
  • compatibility_flags - enables features like Node.js built-in support

As you add services (D1, R2, KV), you add binding declarations here. Each subsequent quickstart shows the new config section.

Typed Environment Bindings

Run npx wrangler types to generate worker-configuration.d.ts. This file contains TypeScript types for all your bindings declared in wrangler.jsonc:

npx wrangler types

For a fresh project with no bindings, it generates an empty Env interface. As you add D1, R2, KV bindings to wrangler.jsonc, re-run the command and the interface updates automatically.

// worker-configuration.d.ts (auto-generated)
interface Env {
  // Bindings appear here after you add them to wrangler.jsonc
  // and re-run `npx wrangler types`
}

Use this type with Hono’s generic parameter so c.env is fully typed:

import { Hono } from "hono";

// Use the auto-generated Env type from worker-configuration.d.ts
const app = new Hono<{ Bindings: Env }>();

Tip: Add npx wrangler types to your build script or run it after changing wrangler.jsonc. It keeps your types in sync with your config automatically.

Write a Hono App

Replace src/index.ts with a basic API:

import { Hono } from "hono";

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

app.get("/", (c) => {
  return c.json({ name: "Webhook Hub", status: "running" });
});

app.get("/health", (c) => {
  return c.text("ok");
});

app.post("/webhook/:source", async (c) => {
  const source = c.req.param("source");
  const payload = await c.req.json();
  // For now, echo the payload back. Later quickstarts add D1, R2, KV.
  return c.json({ received: true, source, payload }, 202);
});

// 404 fallback
app.notFound((c) => {
  return c.json({ error: "not found" }, 404);
});

export default app;

Three things to notice:

  1. Hono<{ Bindings: Env }> - passes the auto-generated Env type so c.env is typed
  2. c.req.param("source") - Hono’s typed route parameters
  3. export default app - Hono implements the Worker fetch handler interface, so this just works

Local Development

npx wrangler dev

This starts workerd locally on http://localhost:8787 with hot reload. Test your routes:

# Health check
curl http://localhost:8787/health

# Post a test webhook
curl -X POST http://localhost:8787/webhook/github \
  -H "Content-Type: application/json" \
  -d '{"event": "push", "repo": "my-project"}'

wrangler dev runs on the same workerd runtime as production. If it works locally, it works deployed.

Deploy

npx wrangler deploy

First deploy prompts you to log in (if you haven’t). After that, your Worker is live at:

https://webhook-hub.<your-subdomain>.workers.dev

Every subsequent npx wrangler deploy pushes updates in seconds. No build pipeline, no container images, no cold starts.

Error Handling

Add a global error handler so uncaught exceptions return JSON instead of a bare 500:

app.onError((err, c) => {
  console.error(`${c.req.method} ${c.req.path}:`, err.message);
  return c.json({ error: "internal server error" }, 500);
});

In production, errors logged with console.error appear in npx wrangler tail (live log stream) and in the Workers dashboard under Logs.

Viewing Logs

# Stream live logs from your deployed Worker
npx wrangler tail

This shows every request with status code, timing, and any console.log output. Essential for debugging in production.

What’s Next

This Worker becomes the Webhook Hub API in later quickstarts. Each one adds a Cloudflare service:

  • D1 CRUD - store webhook payloads in a database
  • R2 Files - offload large payloads to object storage
  • KV Caching - add per-source rate limiting
  • Turnstile - protect the dashboard with bot verification

For deeper coverage of wrangler, Vitest, and the Vite plugin, see Dev Tooling.