Write a service
ES modules with a fetch handler, on the web platform.
A service is ES modules. The main module's default export is an object with
a fetch handler and, optionally, job and message handlers:
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url)
if (url.pathname === "/api/notes" && request.method === "POST") {
const { text } = await request.json()
const { lastRowId } = await env.DB.run("INSERT INTO notes (text) VALUES (?)", text)
return Response.json({ id: lastRowId }, { status: 201 })
}
return Response.json(await env.DB.query("SELECT * FROM notes ORDER BY id DESC LIMIT 50"))
},
async job(job, env, ctx) {}, // runs jobs and crons
async message(event, env, ctx) {}, // receives WebSocket messages
}The runtime
Services run on workerd, the
Cloudflare Workers runtime: the web platform APIs (fetch, Request,
Response, streams, crypto.subtle, URL, TextEncoder and the rest) and
node:* modules (node:crypto, node:buffer and others).
envholds the service's bindings, its vars and secrets.request.urlhas the public host; the client's address is inX-Forwarded-For.- WebSockets created in the service (
new WebSocketPair()) do not work: use the realtime binding.
Files and modules
Files are modules by their extension:
| Extension | Imports as |
|---|---|
.js, .mjs | An ES module |
.json | Data |
.txt .html .htm .css .md .svg .xml .csv | A string |
.wasm | A WebAssembly.Module |
| Anything else | An ArrayBuffer |
Import them with relative paths: import page from "./index.html".
JavaScript only, with no build step or npm installs: write plain modules, or bundle and compile TypeScript yourself and deploy the output.
Files under public/ are not modules: the assets
binding serves them as they are. Put HTML, CSS, browser JavaScript, images
and fonts there.
State
A service's process keeps nothing between requests. It starts on the first request (in about 40 ms), stops after a while without work, and is replaced by each new version. Keep every piece of state in a binding: a database, files, jobs or realtime channels.
Limits
Each service has its own heap and a disk quota for its data, and a request that keeps the CPU busy too long restarts it. The numbers are in Limits; outbound requests are in Operate.