Zetsu is a highly opinionated, production-ready, and battle-tested Edge API template built on Hono and designed exclusively for Cloudflare Workers. It was created to provide a bulletproof foundation for capturing waitlist signups securely, but its modular architecture makes it the perfect starting point for any high-performance Edge API.
Zetsu doesn't just "work"; it is engineered for absolute resilience, observability, and scale at the Edge:
- Edge Native: Zero Node.js dependencies. Runs directly on the V8 isolate via Cloudflare Workers for sub-millisecond cold starts and global distribution.
- Bot Mitigation: Built-in, invisible CAPTCHA integration using Cloudflare Turnstile to ensure your API only processes requests from real humans.
- Robust Observability: Context-injected, structured JSON logging using Pino, complete with
requestIddistributed tracing andServer-Timingheaders. - Fail-Safe Configuration: Manual, strict environment variable validation ensures the Worker fails fast with clear errors rather than crashing silently mid-request.
- Type-Safe Validation: Payload validation via Zod, with schemas decoupled from routes for maximum reusability.
- Modular Architecture: Strict separation of concerns (Routes → Implementations → Services) makes testing and scaling the codebase trivial.
- Framework: Hono
- Runtime: Cloudflare Workers
- Validation: Zod &
@hono/zod-validator - Logging: Pino
- Linting: Oxlint (configured with strict deprecation rules)
- Formatting: Prettier
- Integrations: Resend SDK (Segments API)
Zetsu follows a clean, highly decoupled architecture:
src/
├── index.ts # Master entry point, global middleware, error handlers
├── types.ts # Global type definitions (Bindings, Context Variables)
├── lib/
│ ├── config.ts # Manual, fail-safe environment validation
│ └── logger.ts # Edge-optimized Pino logger factory
├── schemas/
│ └── waitlist.ts # Zod validation schemas
├── services/
│ ├── resend.ts # Resend API integration logic
│ └── turnstile.ts # Cloudflare Turnstile verification logic
├── implementations/
│ └── waitlist.ts # Core business logic (orchestrating services)
└── routes/
├── health.ts # Health check definitions
└── waitlist.ts # Route-to-middleware/implementation mapping
- Node.js (v20+ recommended)
npm
Clone the repository and install dependencies:
git clone https://github.com/enytc/zetsu.git
cd zetsu
npm installCloudflare Workers use .dev.vars for local secrets instead of standard .env files.
- Copy the example file:
cp .env.example .dev.vars
- Open
.dev.varsand fill in your actual credentials:RESEND_API_KEY: Your API key from the Resend dashboard.RESEND_SEGMENT_ID: The specific Segment ID where waitlist users should go.TURNSTILE_SECRET_KEY: Your Secret Key from the Cloudflare Turnstile dashboard.
Run the application using Wrangler's local development simulator:
npm run devThe API will be available at http://localhost:8787.
Zetsu enforces strict code quality standards to prevent regressions. Before committing or deploying, run:
# Type checking without emitting compiled files
npm run type-check
# Ultra-fast linting (will fail if deprecated APIs are used)
npm run lint
# Code formatting
npm run formatDeploying to Cloudflare's global edge network takes seconds, but requires properly configuring your production secrets first.
Login to your Cloudflare account via the Wrangler CLI:
npx wrangler loginCRITICAL: Never hardcode secrets in wrangler.toml. You must inject them securely into Cloudflare's infrastructure. Run the following commands and paste your keys when prompted:
npx wrangler secret put RESEND_API_KEY
npx wrangler secret put RESEND_SEGMENT_ID
npx wrangler secret put TURNSTILE_SECRET_KEYOpen wrangler.toml. By default, Zetsu deploys to a *.workers.dev subdomain.
If you want to use a custom domain, add a routes array to your environment block in wrangler.toml:
[env.production]
name = "zetsu"
route = { pattern = "api.yourdomain.com/*", custom_domain = true }Once your secrets are set and your wrangler.toml is configured, launch it:
npm run deployNote: This command uses wrangler deploy, which automatically reads the wrangler.toml configuration and pushes your code to the Edge.
If you contribute to or extend this template, please adhere to these core philosophies:
- Fail-Fast Initialization: If a required environment variable is missing, the application should throw a critical error during middleware initialization, rather than failing silently deep inside a service.
- Context is King: Never rely on global state (
process.env). Always inject dependencies (likeloggerandconfig) into the Hono Context (c.set/c.get). This ensures safe execution in the shared V8 isolate environment. - Log Everything (Securely): Use the request-scoped Pino logger for all operations. Ensure
requestIdis always attached. Never log secrets. - Graceful Degradation: When integrating with external APIs (like Resend), handle their failures gracefully. If a user tries to join a waitlist they are already on, or if the email service has a minor hiccup, log the error internally but return a success message to the frontend to maintain a frictionless UX.
- No Deprecated Code: The linter is strictly configured to reject any code marked with
@deprecated. Always use the modern alternative (e.g.,z.email()instead ofz.string().email()).
Zetsu is designed to be mathematically verified before it ever reaches production. We use Jest for a comprehensive suite of Unit and End-to-End (E2E) tests.
- Unit Tests (
tests/unit/): Verifies discrete functions and services (like configuration validation and external API SDKs). External HTTP calls are strictly mocked. - E2E Tests (
tests/e2e/): Validates the entire request lifecycle. Thanks to Hono's native Fetch API support,app.request()allows us to test the full middleware stack (routing, validation, headers, error handling) in milliseconds without binding to a local port.
To run the test suite and generate a coverage report:
npm run test:coverageOur CI pipeline guarantees that code is never merged unless the test suite passes with high coverage.
This project is licensed under the MIT License - see the LICENSE file for details.