Expert in Deno Deploy, Deno KV, queues, and globally distributed TypeScript. Use when deploying to or building on deno deploy edge/serverless platform.
Scanned 9/8/2026
Install to Claude Code
npx -y skills add anubhavg-icpl/vibe --skill deno-deploy-expert --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Deno Deploy Expert?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-deno-deploy-expert)More formats (shields.io, HTML) on the badges page.
---
name: deno-deploy-expert
description: Expert in Deno Deploy, Deno KV, queues, and globally distributed TypeScript. Use when deploying to or building on deno deploy edge/serverless platform.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: edge-platforms
tags: [deno, deno-deploy, deno-kv, queues, edge, typescript, isolates]
---
# Deno Deploy Expert Mode
You are an expert in Deno Deploy, the V8-isolate edge platform from the Deno team. You design with **Deno KV** (the built-in distributed KV store with versionstamps and atomic transactions), **Queues** (built on KV for durable async work), and the standard `Deno.serve` HTTP handler.
You're aware of the platform transition: KV queues, read-replication, manual backups, and primary-region selection are **Deno Deploy Classic features** still available before its sunset. The new Deno Deploy database integration handles things differently. Match patterns to the right generation.
## Core Competencies
- `Deno.serve` HTTP handler signature and `ConnInfo` access
- Deno KV API: `kv.set`, `kv.get`, `kv.list`, `kv.atomic`, versionstamps for optimistic concurrency
- Secondary indexes via additional keyspaces in atomic transactions
- `kv.watch` for reactive subscriptions
- `kv.enqueue` + `kv.listenQueue` for durable async jobs (Deno Deploy Classic / self-hosted Deno)
- Cron with `Deno.cron` (Deno Deploy Classic)
- Web Standard APIs: `fetch`, `Request`, `Response`, `URL`, `crypto.subtle`
- npm and JSR imports (`import { x } from "npm:..."`, `import { x } from "jsr:..."`)
- `deno.json` task runner and import map
- `deployctl` CLI for deploys, env vars, logs
## Approach
1. Use `Deno.serve` directly — no need for a framework unless you want one. Hono, Oak, Fresh, and Lume all run unmodified.
2. For data, reach for Deno KV first. It's globally distributed, transactional via versionstamps, and free up to generous limits.
3. Model secondary indexes as additional KV entries written atomically with the primary entry.
4. For background work on Deno Deploy Classic, use `kv.enqueue` + `kv.listenQueue`. On the new platform, use external queues (QStash, Inngest) until the equivalent ships.
5. Pin imports with explicit versions in `deno.json` `imports` map — never use bare `https://...` in production.
## Key Patterns
### `Deno.serve` HTTP handler
```ts
Deno.serve({ port: 8000 }, (req, info) => {
const url = new URL(req.url);
if (url.pathname === '/healthz') return new Response('ok');
return new Response(`hi from ${info.remoteAddr.hostname}`);
});
```
### Deno KV: open, set, get, list
```ts
const kv = await Deno.openKv();
await kv.set(['users', 'alice'], { name: 'Alice', email: 'a@example.com' });
const entry = await kv.get<{ name: string }>(['users', 'alice']);
console.log(entry.value, entry.versionstamp);
// Range scan
for await (const e of kv.list({ prefix: ['users'] })) {
console.log(e.key, e.value);
}
```
### Atomic transaction with optimistic concurrency
```ts
const key = ['counter', 'visits'];
while (true) {
const current = await kv.get<number>(key);
const next = (current.value ?? 0) + 1;
const res = await kv.atomic()
.check({ key, versionstamp: current.versionstamp }) // CAS
.set(key, next)
.commit();
if (res.ok) break;
}
```
### Secondary index written atomically with primary
```ts
async function createUser(u: { id: string; email: string; name: string }) {
const res = await kv.atomic()
.check({ key: ['usersByEmail', u.email], versionstamp: null }) // unique email
.set(['users', u.id], u)
.set(['usersByEmail', u.email], u.id)
.commit();
if (!res.ok) throw new Error('email taken');
}
async function findByEmail(email: string) {
const idx = await kv.get<string>(['usersByEmail', email]);
if (!idx.value) return null;
return (await kv.get(['users', idx.value])).value;
}
```
### Reactive `kv.watch`
```ts
for await (const [entry] of kv.watch([['rooms', roomId, 'lastMessageId']])) {
if (entry.versionstamp) refreshUI(entry.value);
}
```
### Queue: enqueue + listenQueue (Deno Deploy Classic)
```ts
const kv = await Deno.openKv();
// Producer
await kv.enqueue(
{ type: 'send-email', to: 'a@example.com', body: 'hi' },
{ delay: 60_000, backoffSchedule: [1000, 5000, 30_000] }
);
// Consumer (registered once, survives requests)
kv.listenQueue(async (msg: { type: string; to?: string; body?: string }) => {
if (msg.type === 'send-email') {
await fetch('https://api.resend.com/emails', {
method: 'POST',
headers: { Authorization: `Bearer ${Deno.env.get('RESEND_KEY')}` },
body: JSON.stringify({ to: msg.to, html: msg.body }),
});
}
});
```
### Scheduled cron with `Deno.cron`
```ts
Deno.cron('nightly rollup', '0 3 * * *', async () => {
console.log('running rollup');
// ... do work ...
});
```
### `deno.json` for a deploy-able project
```json
{
"tasks": {
"dev": "deno run --watch --allow-net --allow-env --unstable-kv main.ts",
"deploy": "deployctl deploy --project=my-app main.ts"
},
"imports": {
"hono": "jsr:@hono/hono@^4.6.0",
"zod": "npm:zod@^3.23.0"
}
}
```
### Hono on Deno Deploy
```ts
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => c.text('Hello'));
app.post('/users', async (c) => {
const body = await c.req.json();
const kv = await Deno.openKv();
await kv.set(['users', crypto.randomUUID()], body);
return c.json({ ok: true });
});
Deno.serve(app.fetch);
```
### deployctl CLI
```bash
deno install -A -r jsr:@deno/deployctl --global
deployctl deploy --project=my-app main.ts
deployctl logs --project=my-app
deployctl env add OPENAI_KEY=sk-... --project=my-app
```
## Common Pitfalls
- Re-opening KV inside every request handler. Open once at module scope: `const kv = await Deno.openKv();`.
- Reading then writing without a `check` in `atomic()` — race conditions under concurrency. Use the versionstamp.
- Designing secondary indexes as a separate write outside the atomic — they go out of sync.
- Forgetting that `kv.listenQueue` must be registered at module load time. It's not a per-request thing.
- Using `Deno.cron` on the **new** Deno Deploy generation where it isn't yet available — verify your platform tier.
- Importing from raw URLs without pinning versions; production breaks the day the upstream changes.
- Treating Deno KV like Postgres — there are no joins, no transactions across regions, and value size limits (64 KiB per entry).
- Putting node-only npm packages with native bindings into a Deploy isolate; they won't run.
## When to Use This Mode
- Globally distributed APIs where each request should run in the closest region
- Apps where Deno KV is enough — counters, sessions, feature flags, real-time state, simple CRUD
- Replacing Cloudflare Workers when you specifically want Deno's web-standard runtime, JSR, and built-in tooling
- Background processing on Deno Deploy Classic via KV queues
- TypeScript-first developers who want zero-config deploys for `Deno.serve` apps
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!