Cloudflare Workers with Quill
Quill makes it easy to build Cloudflare Workers — serverless functions that run at the edge, close to your users. With the worker on fetch syntax, you can build a full API in 15 lines of readable code.
Getting Started
The fastest way to start is with the scaffold command:
quill worker my-api
cd my-api
npm install
This creates a project with:
worker.quill— your worker source codewrangler.toml— Cloudflare configurationpackage.json— with wrangler as a dev dependency
Build and run locally:
npm run dev
This compiles your Quill code to JavaScript and starts a local Wrangler dev server.
Manual setup
If you prefer to set things up yourself:
- Create a
worker.quillfile - Compile it:
quill build worker.quill - Create a
wrangler.tomlpointing toworker.js - Run with
npx wrangler dev worker.js
Your First Worker
A minimal Cloudflare Worker in Quill:
worker on fetch with request:
respond "Hello from Quill!"
This compiles to a standard Cloudflare Worker using ES modules:
export default {
async fetch(request) {
return new Response("Hello from Quill!");
}
};
Routing
Use the standard URL API and if statements for routing:
worker on fetch with request:
url is new URL(request.url)
path is url.pathname
if path is "/":
respond html "<h1>Welcome!</h1>"
if path is "/about":
respond html "<h1>About Us</h1>"
respond "Not found" status 404
You can use starts with for prefix matching by using JavaScript's startsWith method in expressions.
JSON APIs
Return JSON responses with the respond json keyword:
worker on fetch with request:
url is new URL(request.url)
path is url.pathname
if path is "/api/hello":
name is url.searchParams.get("name")
if name is nothing:
name is "World"
respond json { message: "Hello, {name}!" }
if path is "/api/status":
respond json { status: "ok", version: "1.0.0" }
respond json { error: "Not found" } status 404
The respond json keyword automatically:
- Serializes the object with
JSON.stringify() - Sets the
Content-Type: application/jsonheader
Response types
| Quill syntax | Content-Type |
|---|---|
respond "text" |
text/plain (default) |
respond json { ... } |
application/json |
respond html "<h1>...</h1>" |
text/html |
Add a status code with the status keyword:
respond "Not found" status 404
respond json { error: "Unauthorized" } status 401
Complete JSON API Example
Here is a full example of a JSON API worker that manages a list of tasks. It handles GET and POST requests with proper error handling:
-- task-api.quill
-- A complete JSON API for managing tasks
worker on fetch with request env:
url is new URL(request.url)
path is url.pathname
method is request.method
-- GET /api/tasks -- list all tasks
if path is "/api/tasks" and method is "GET":
tasks is await env.TASKS_KV.list()
items are []
for each key in tasks.keys:
value is await env.TASKS_KV.get(key.name)
push(items, parseJSON(value))
respond json { tasks: items, count: length(items) }
-- POST /api/tasks -- create a new task
if path is "/api/tasks" and method is "POST":
body is await request.json()
if body.title is nothing:
respond json { error: "title is required" } status 400
id is uuid()
task is { id: id, title: body.title, done: no }
await env.TASKS_KV.put(id, toJSON(task))
respond json task status 201
-- GET /api/health -- health check
if path is "/api/health":
respond json { status: "ok", timestamp: now() }
-- Catch-all for unknown routes
respond json { error: "Not found", path: path } status 404
This worker uses KV storage to persist tasks. See the KV Storage section below for how to configure it.
KV Storage
Cloudflare Workers KV is a key-value store available at the edge. To use it, add the env parameter to your worker handler:
worker on fetch with request env:
url is new URL(request.url)
path is url.pathname
if path is "/get":
key is url.searchParams.get("key")
value is await env.MY_KV.get(key)
if value is nothing:
respond json { error: "Key not found" } status 404
respond json { key: key, value: value }
if path is "/set":
key is url.searchParams.get("key")
val is url.searchParams.get("value")
await env.MY_KV.put(key, val)
respond json { success: yes }
respond "Not found" status 404
You also need to configure the KV binding in wrangler.toml:
name = "my-worker"
main = "worker.js"
compatibility_date = "2024-01-01"
[[kv_namespaces]]
binding = "MY_KV"
id = "your-namespace-id"
Create a KV namespace with the Wrangler CLI:
npx wrangler kv:namespace create "MY_KV"
This will output the namespace ID to paste into your wrangler.toml. See the Cloudflare KV documentation for more details.
Deployment
Deploy your worker to Cloudflare's global network:
Step-by-step deployment
# 1. Install wrangler (if not already installed)
npm install -g wrangler
# 2. Log in to your Cloudflare account
npx wrangler login
# 3. Build your Quill code to JavaScript
quill build worker.quill
# 4. Test locally before deploying
npx wrangler dev worker.js
# 5. Deploy to Cloudflare's network
npx wrangler deploy
Or if you used quill worker to scaffold your project, simply run:
# Build and deploy in one step
npm run deploy
Useful wrangler commands
| Command | What it does |
|---|---|
npx wrangler dev |
Start a local dev server for testing |
npx wrangler deploy |
Deploy to production |
npx wrangler tail |
View live logs from your deployed worker |
npx wrangler kv:namespace create "MY_KV" |
Create a new KV namespace |
npx wrangler secret put API_KEY |
Add a secret environment variable |
Your worker will be available at https://your-worker.your-subdomain.workers.dev.
For custom domains, see the Cloudflare Workers routing documentation.
Next Steps
- Explore the Cloudflare Workers documentation for the full Workers API.
- Learn about Workers KV for edge storage.
- Check out the Examples page for more Quill programs.
- Join the Quill Discord community to share your project and get help.