Deno Deploy
Deno Deploy edge functions for globally distributed serverless applications
You are an expert in Deno Deploy for building and shipping globally distributed edge functions and serverless applications.
## Key Points
- **Writing to the filesystem.** `Deno.writeTextFile` works for files bundled with the deployment but the filesystem is read-only for runtime writes. Use Deno KV for all persistent storage.
- **Keep handlers fast** — Deploy has a per-request CPU time limit (typically 50 ms of CPU, wall-clock can be longer during I/O waits). Offload heavy work to Deno KV queues.
- **Use Deno KV for state** — avoid external databases when possible; KV is co-located and has no connection overhead.
- **Structure KV keys hierarchically** — `["org", orgId, "users", userId]` enables efficient prefix listing and logical grouping.
- **Use atomic operations** for any read-modify-write cycle to prevent race conditions.
- **Set environment variables through the dashboard**, not in code. Never commit secrets.
- **Use `Deno.cron`** instead of external schedulers for periodic tasks.
- **Exceeding CPU limits** — CPU-heavy computation (image processing, large JSON parsing) can hit the wall. Stream responses or break work into queue jobs.
- **Assuming local filesystem access** — `Deno.readTextFile` works for files bundled with your deployment (static assets) but you cannot write to the filesystem. Use KV instead.
- **KV key size limits** — keys can have up to 10 parts, each part up to 2 KB. Values are limited to 64 KB. Design your data model accordingly.
- **Forgetting versionstamp in atomic checks** — omitting the check step allows last-write-wins, which silently loses data.
- **Cold start assumptions** — global variables reset between invocations. Do not rely on in-memory state persisting.
## Quick Example
```typescript
const channel = new BroadcastChannel("events");
channel.onmessage = (event) => {
console.log("Received:", event.data);
};
channel.postMessage({ type: "cache-invalidate", key: "products" });
```
```bash
deployctl env set MY_SECRET=supersecret --project=my-project
```skilldb get deno-bun-skills/Deno DeployFull skill: 182 linesDeno Deploy — Modern JS Runtimes
You are an expert in Deno Deploy for building and shipping globally distributed edge functions and serverless applications.
Overview
Deno Deploy is a serverless platform that runs Deno code on a global edge network. Functions execute close to users across 35+ regions with zero cold-start configuration. It uses the same Web Standard APIs as local Deno, supports Deno KV for globally consistent storage, and integrates directly with GitHub for automatic deployments.
Core Concepts
Edge Function Model
Every deployment is a V8 isolate — lightweight, fast to start, and billed per-request. There is no container or VM to configure. Your code receives a Request and returns a Response, exactly like the local Deno.serve API.
Deno KV (Built-in Database)
Deno Deploy includes Deno KV, a globally replicated key-value store with strong consistency within a region and eventual consistency across regions.
const kv = await Deno.openKv(); // no connection string needed on Deploy
// Set a value
await kv.set(["users", "u_123"], { name: "Alice", plan: "pro" });
// Get a value
const entry = await kv.get(["users", "u_123"]);
console.log(entry.value); // { name: "Alice", plan: "pro" }
// List by prefix
const iter = kv.list({ prefix: ["users"] });
for await (const entry of iter) {
console.log(entry.key, entry.value);
}
// Atomic transactions
await kv.atomic()
.check({ key: ["users", "u_123"], versionstamp: entry.versionstamp })
.set(["users", "u_123"], { ...entry.value, plan: "enterprise" })
.commit();
BroadcastChannel
Communicate between isolates in the same deployment across regions:
const channel = new BroadcastChannel("events");
channel.onmessage = (event) => {
console.log("Received:", event.data);
};
channel.postMessage({ type: "cache-invalidate", key: "products" });
Queues
Deno KV includes a built-in message queue for background and deferred work:
const kv = await Deno.openKv();
// Enqueue a job
await kv.enqueue({ type: "send-email", to: "user@example.com" }, {
delay: 5000, // optional delay in ms
});
// Listen for jobs
kv.listenQueue(async (msg) => {
if (msg.type === "send-email") {
await sendEmail(msg.to);
}
});
Implementation Patterns
REST API on the Edge
Deno.serve(async (req: Request): Promise<Response> => {
const url = new URL(req.url);
const kv = await Deno.openKv();
if (req.method === "GET" && url.pathname === "/api/items") {
const items = [];
for await (const entry of kv.list({ prefix: ["items"] })) {
items.push(entry.value);
}
return Response.json(items);
}
if (req.method === "POST" && url.pathname === "/api/items") {
const body = await req.json();
const id = crypto.randomUUID();
await kv.set(["items", id], { id, ...body, createdAt: Date.now() });
return Response.json({ id }, { status: 201 });
}
return new Response("Not Found", { status: 404 });
});
Scheduled (Cron) Functions
Deno.cron("daily-cleanup", "0 3 * * *", async () => {
const kv = await Deno.openKv();
const cutoff = Date.now() - 30 * 24 * 60 * 60 * 1000;
for await (const entry of kv.list({ prefix: ["logs"] })) {
if ((entry.value as any).timestamp < cutoff) {
await kv.delete(entry.key);
}
}
});
Environment Variables and Secrets
Set secrets in the Deno Deploy dashboard or via deployctl:
deployctl env set MY_SECRET=supersecret --project=my-project
const secret = Deno.env.get("MY_SECRET");
Deployment via GitHub or CLI
# Install the CLI
deno install -A jsr:@deno/deployctl
# Deploy directly
deployctl deploy --project=my-project --entrypoint=main.ts
# Or link a GitHub repo in the dashboard for auto-deploy on push
Core Philosophy
Deno Deploy is designed around the principle that serverless functions should be as simple as writing a request handler. Your code receives a Request and returns a Response, exactly as Deno.serve works locally. There is no framework, no configuration file, and no container to manage. This simplicity is possible because Deploy runs V8 isolates rather than containers, giving you near-instant cold starts and global distribution without operational complexity.
The co-location of compute and storage is central to Deploy's architecture. Deno KV is not just a convenience; it is the recommended storage layer because it runs on the same edge network as your code. There is no connection string, no driver, and no network hop to a remote database. This eliminates the latency and operational overhead of connecting to external databases from edge functions, which is the primary bottleneck in most serverless architectures.
Deploy's pricing and execution model enforce a clear constraint: handlers must be fast and efficient. CPU time is limited per request, global state does not persist between invocations, and the filesystem is read-only. These are not limitations to work around but design constraints to embrace. If your workload is CPU-heavy, break it into queue jobs. If your data needs persistence, use KV. If your state must survive requests, store it in KV rather than in global variables.
Anti-Patterns
-
Performing CPU-heavy computation in request handlers. Image processing, large JSON parsing, or complex calculations can exceed Deploy's per-request CPU limit. Offload heavy work to Deno KV queues where processing can happen outside the request lifecycle.
-
Using global variables for persistent state. Global variables reset between invocations because isolates are recycled. Data that must survive requests belongs in Deno KV, not in module-scope variables.
-
Writing to the filesystem.
Deno.writeTextFileworks for files bundled with the deployment but the filesystem is read-only for runtime writes. Use Deno KV for all persistent storage. -
Omitting versionstamp checks in atomic KV operations. Without a
checkstep, atomic operations use last-write-wins semantics, which silently loses concurrent updates. Always read the entry's versionstamp and include it in the atomic check for read-modify-write cycles. -
Storing large blobs in KV values. KV values are limited to 64 KB and keys to 2 KB per part. Attempting to store images, files, or large JSON objects in KV values will fail. Use an external object store for large assets and store only references in KV.
Best Practices
- Keep handlers fast — Deploy has a per-request CPU time limit (typically 50 ms of CPU, wall-clock can be longer during I/O waits). Offload heavy work to Deno KV queues.
- Use Deno KV for state — avoid external databases when possible; KV is co-located and has no connection overhead.
- Structure KV keys hierarchically —
["org", orgId, "users", userId]enables efficient prefix listing and logical grouping. - Use atomic operations for any read-modify-write cycle to prevent race conditions.
- Set environment variables through the dashboard, not in code. Never commit secrets.
- Use
Deno.croninstead of external schedulers for periodic tasks.
Common Pitfalls
- Exceeding CPU limits — CPU-heavy computation (image processing, large JSON parsing) can hit the wall. Stream responses or break work into queue jobs.
- Assuming local filesystem access —
Deno.readTextFileworks for files bundled with your deployment (static assets) but you cannot write to the filesystem. Use KV instead. - KV key size limits — keys can have up to 10 parts, each part up to 2 KB. Values are limited to 64 KB. Design your data model accordingly.
- Forgetting versionstamp in atomic checks — omitting the check step allows last-write-wins, which silently loses data.
- Cold start assumptions — global variables reset between invocations. Do not rely on in-memory state persisting.
- CORS headers — Deploy does not add CORS headers automatically. You must set
Access-Control-Allow-Originyourself if serving browser clients from a different origin.
Install this skill directly: skilldb add deno-bun-skills
Related Skills
Bun Basics
Bun runtime fundamentals including speed optimizations, built-in APIs, and package management
Bun Bundler
Using Bun as a bundler for frontend assets and as a fast test runner
Compatibility
Node.js compatibility layers in Deno and Bun for running existing npm packages and Node APIs
Deno Basics
Deno runtime fundamentals including permissions, module system, and built-in tooling
Elysia Bun
Elysia web framework on Bun for type-safe, high-performance HTTP APIs
Fresh Framework
Fresh full-stack web framework for Deno with islands architecture and zero client JS by default