deno

$npx mdskill add TerminalSkills/skills/deno

Build secure JavaScript/TypeScript apps using Deno's runtime and tooling

  • Solves tasks like server creation, CLI tool development, and script automation with Deno
  • Leverages Deno APIs, npm compatibility, and web standards for execution
  • Analyzes commands and permissions to determine appropriate runtime actions
  • Delivers results via Deno's built-in tooling and runtime execution output
SKILL.md
.github/skills/denoView on GitHub ↗
---
name: deno
description: >-
  Assists with building secure JavaScript and TypeScript applications using the Deno runtime.
  Use when creating servers, CLI tools, or scripts with Deno's built-in tooling, permission model,
  npm compatibility, and web standards APIs. Trigger words: deno, deno deploy, deno serve, deno kv,
  deno permissions, secure runtime, jsr.
license: Apache-2.0
compatibility: "Deno 2.x. TypeScript first-class. npm compatibility built-in."
metadata:
  author: terminal-skills
  version: "1.0.0"
  category: development
  tags: ["deno", "typescript", "runtime", "secure", "web-standards"]
---

# Deno

## Overview

Deno is a secure JavaScript/TypeScript runtime built on V8. It runs TypeScript natively without config, is secure by default (explicit permissions required), and is fully compatible with npm packages. Deno 2 adds backwards compatibility with Node.js APIs and `package.json`, making it a viable drop-in replacement for many Node.js projects. Built-in tooling includes a formatter, linter, test runner, and compiler.

## Instructions

- When creating servers, use `Deno.serve()` for high-performance HTTP handling with Web Standards Request/Response, and enable parallel workers with `deno serve --parallel` for multi-core utilization.
- When configuring security, specify permissions explicitly (`--allow-read`, `--allow-net`, `--allow-env`) scoped to specific paths, hosts, or variable names. Never deploy with `--allow-all`.
- When managing dependencies, use JSR (`jsr:`) for versioned, type-checked packages, `npm:` specifier for npm packages, and configure import maps in `deno.json` for clean paths.
- When writing tests, use `Deno.test()` with `@std/assert` assertions, `@std/testing` for mocking, and `deno test --coverage` for coverage reports. Deno's sanitizers detect resource leaks automatically.
- When building CLI tools, use `deno compile` to produce standalone executables that cross-compile for Linux, macOS, and Windows with no runtime dependency.
- When deploying to the edge, use Deno Deploy with Deno KV for key-value storage, `Deno.cron()` for scheduled tasks, and queues for background processing.
- When using Deno KV, structure keys hierarchically (`["users", id, "profile"]`), use `atomic()` for transactions, and configure TTL with `expireIn` for automatic expiration.

## Permissions Model

Deno is secure by default — all external access must be explicitly granted:

| Flag | Grants access to |
|---|---|
| `--allow-net` | Network (fetch, listen) |
| `--allow-read` | File system reads |
| `--allow-write` | File system writes |
| `--allow-env` | Environment variables |
| `--allow-run` | Subprocess execution |
| `--allow-ffi` | Native libraries |
| `--allow-all` or `-A` | Everything (avoid in prod) |

Fine-grained permissions:

```bash
deno run --allow-net=api.stripe.com --allow-read=./data main.ts
```

## npm Compatibility

Import npm packages directly with the `npm:` prefix:

```typescript
import express from "npm:express";
import { z } from "npm:zod";

const app = express();
app.get("/", (_req, res) => {
  res.json({ message: "Hello from Deno + Express!" });
});
app.listen(3000);
```

Or declare in `deno.json`:

```json
{
  "imports": {
    "express": "npm:express@^4",
    "zod": "npm:zod@^3"
  }
}
```

## HTTP Server

```typescript
// Built-in Deno.serve — no imports needed
Deno.serve({ port: 3000 }, async (req: Request) => {
  const url = new URL(req.url);

  if (url.pathname === "/health") {
    return Response.json({ status: "ok" });
  }

  if (req.method === "POST" && url.pathname === "/echo") {
    const body = await req.json();
    return Response.json(body);
  }

  return new Response("Not Found", { status: 404 });
});
```

## Built-in Test Runner

```typescript
import { assertEquals, assertThrows } from "jsr:@std/assert";

Deno.test("add works correctly", () => {
  assertEquals(1 + 2, 3);
});

Deno.test({
  name: "async fetch test",
  permissions: { net: true },
  async fn() {
    const res = await fetch("https://httpbin.org/get");
    assertEquals(res.status, 200);
  },
});
```

```bash
deno test                        # Run all tests
deno test --watch                # Watch mode
deno test --coverage=coverage/   # With coverage
```

## Built-in Tooling

```bash
deno fmt                 # Format code (Prettier-compatible)
deno lint                # Lint code
deno check main.ts       # Type-check without running
deno compile main.ts     # Compile to standalone binary
deno info main.ts        # Show module dependency tree
```

## deno.json Configuration

```json
{
  "tasks": {
    "dev": "deno run --allow-net --allow-read --allow-env --watch src/main.ts",
    "test": "deno test --allow-net",
    "build": "deno compile --allow-net --allow-read src/main.ts"
  },
  "imports": {
    "zod": "npm:zod@^3",
    "@std/assert": "jsr:@std/assert@^1",
    "@hono/hono": "jsr:@hono/hono@^4"
  },
  "lint": { "rules": { "include": ["no-unused-vars"] } },
  "fmt": { "useTabs": false, "lineWidth": 100 }
}
```

## Deno Deploy

```typescript
// main.ts — deploy to Deno Deploy
Deno.serve((req) => {
  const { pathname } = new URL(req.url);
  if (pathname === "/") {
    return new Response("Hello from the edge!");
  }
  return new Response("Not Found", { status: 404 });
});
```

```bash
deno install -A jsr:@deno/deployctl
deployctl deploy --project=my-project main.ts
```

## Examples

### Example 1: Build a REST API with Deno KV

**User request:** "Create an API with Deno that stores data in Deno KV"

**Actions:**
1. Create HTTP server with `Deno.serve()` and route matching
2. Open KV store with `Deno.openKv()` and define key structure
3. Implement CRUD operations using `kv.get()`, `kv.set()`, and `kv.atomic()`
4. Set explicit permissions in `deno.json` task definitions

**Output:** A secure API with embedded key-value storage, ready for Deno Deploy.

### Example 2: Compile a CLI tool for distribution

**User request:** "Create a Deno CLI tool that can be distributed as a single binary"

**Actions:**
1. Build the CLI with argument parsing using `@std/cli`
2. Add file and network permissions scoped to required resources
3. Write tests with `Deno.test()` and run with `deno test`
4. Compile to standalone binaries with `deno compile --target` for each platform

**Output:** Cross-platform standalone executables with no runtime dependency.

## Guidelines

- Always specify permissions explicitly in production; never deploy with `--allow-all`.
- Use `deno.json` imports map for clean import paths instead of raw URLs.
- Prefer JSR (`jsr:`) over URL imports for versioned, type-checked, immutable packages.
- Use `npm:` specifier for npm packages directly — no install step needed.
- Run `deno fmt` and `deno lint` in CI for zero-config formatting and linting.
- Use `Deno.serve()` over third-party frameworks for simple APIs; it is faster and lighter.
- Compile to standalone binary with `deno compile` for distribution with no runtime dependency.
- Deno 2 is backward-compatible with `package.json` — Node.js projects often work without changes.
- Use Deno Deploy for serverless edge deployment with zero infrastructure.
More from TerminalSkills/skills