Ploy Start
Getting Started
Build type-safe Cloudflare Workers with Ploy Start framework.
Ploy Start
Ploy Start is a type-safe framework for building Cloudflare Workers with automatic type inference, Zod validation, and built-in support for databases, queues, and workflows.
Features
- Type-Safe Routing - Full TypeScript inference for params, query, body, and response
- Zod Validation - Automatic request/response validation with Zod schemas
- Drizzle ORM - Built-in database integration with Drizzle
- Queue Handlers - Type-safe message queue processing
- Workflow Handlers - Durable workflow execution with step functions
- OpenAPI Generation - Auto-generated API documentation
- Built-in Middleware - CORS, logging, auth, and rate limiting
Installation
pnpm add @meetploy/start
pnpm add -D drizzle-ormMinimal Example
The simplest Ploy Start worker:
import { ploy, z } from "@meetploy/start";
const worker = ploy()
.get(
"/",
{
response: z.object({ message: z.string() }),
},
async () => {
return { message: "Hello from Ploy Start!" };
},
)
.build();
export default worker;That's it! The ploy() function creates a builder, you chain route definitions, and .build() generates the worker export.
Project Setup
Directory Structure
my-worker/
├── src/
│ ├── index.ts # Worker entry point
│ └── env.d.ts # Environment types
├── package.json
├── tsconfig.json
├── wrangler.json
└── ploy.yamlpackage.json
{
"name": "my-worker",
"version": "0.0.0",
"private": true,
"type": "module",
"main": "src/index.ts",
"scripts": {
"build": "tsc --noEmit && wrangler build",
"types": "ploy types"
},
"dependencies": {
"@meetploy/start": "latest",
"@meetploy/types": "latest"
},
"devDependencies": {
"typescript": "^5.9.0",
"wrangler": "^4.0.0"
}
}ploy.yaml
kind: worker
build: pnpm build
out: distEnvironment Types
Generate environment types with the Ploy CLI:
pnpm typesThis creates env.d.ts with your bindings typed.
Complete Example
Here's a full example with all features:
import { ploy, withDrizzle, cors, logger, z } from "@meetploy/start";
import * as schema from "./schema.js";
const worker = ploy<PloyEnv>()
// Middleware
.use(cors())
.use(logger())
// Database state
.state(withDrizzle("DB", schema))
// OpenAPI docs
.openapi({
path: "/docs",
info: { title: "My API", version: "1.0.0" },
})
// Routes
.get(
"/",
{
response: z.object({ message: z.string() }),
},
async () => {
return { message: "Hello!" };
},
)
.get(
"/users",
{
response: z.object({
users: z.array(
z.object({
id: z.number(),
name: z.string(),
}),
),
}),
},
async (ctx) => {
const users = await ctx.state.db.select().from(schema.users);
return { users };
},
)
.build();
export default worker;Method Chaining
Ploy Start uses method chaining with TypeScript generics to accumulate types. Each method returns a new typed builder:
const worker = ploy<PloyEnv>()
.state(withDrizzle("DB", schema)) // Adds db to state
.use(cors()) // Adds middleware
.get("/users", {...}, handler) // Adds GET /users route
.post("/users", {...}, handler) // Adds POST /users route
.queue("TASKS", {...}, handler) // Adds queue handler
.workflow("flow", {...}, handler) // Adds workflow handler
.build(); // Returns { fetch, message?, workflows? }The final .build() call returns a PloyHandler<PloyEnv> compatible object with:
fetch- HTTP request handlermessage- Queue message handler (if queues defined)workflows- Workflow handlers (if workflows defined)
What's Next
How is this guide?
Last updated on