---
title: "denoland/skills"
description: "Deno skills for AI coding assistants. Covers using Deno as a package manager and runtime, migrating from npm/yarn/pnpm/bun, Fresh, and Deno Deploy."
source: https://github.com/denoland/skills
ref: main
license: MIT
licenseName: "MIT License"
canonical: https://skillsdocs.com/denoland/skills
base: https://github.com/denoland/skills/blob/main/
provenance: authored
chapters: 5
inlined: 5
withheld: 0
words: 3811
updated: 2026-07-29T15:51:22Z
generator: "Skills Docs"
---

> **denoland/skills** — every Agent Skill in this repository, inlined verbatim.
>
> Canonical HTML: https://skillsdocs.com/denoland/skills
> Per-skill Markdown: https://skillsdocs.com/denoland/skills/<skill>.md
> Machine manifest: https://skillsdocs.com/denoland/skills/.well-known/agent-skills/index.json
> JSON: https://skillsdocs.com/api/v1/books/denoland/skills
> Install: `npx skills add denoland/skills`
> Upstream: https://github.com/denoland/skills @ `main`
> Licence: MIT
>
> Content is mirrored from GitHub and © its authors, served unmodified. Takedown: https://github.com/DreambaseAI/skillsdocs/issues/new?labels=takedown&title=Takedown+request

# denoland/skills

Deno skills for AI coding assistants. Covers using Deno as a package manager and runtime, migrating from npm/yarn/pnpm/bun, Fresh, and Deno Deploy.

- **Skills:** 5
- **Inlined:** 5 (licence detected)
- **Words:** 3,811
- **Reading time:** 18 min
- **Stars:** 99

## Table of contents

1. [deno-deploy](https://skillsdocs.com/denoland/skills/deno-deploy.md) — Use when deploying Deno apps to production, asking about Deno Deploy, or working with `deno deploy` CLI commands. Covers deployment workflows, environment vari…
2. [deno-frontend](https://skillsdocs.com/denoland/skills/deno-frontend.md) — Use when building a web frontend with Deno — running React, Vite, Astro, SvelteKit, Next.js, Nuxt or other npm frameworks under Deno, or working with Fresh, De…
3. [deno-sandbox](https://skillsdocs.com/denoland/skills/deno-sandbox.md) — Use when building features that execute untrusted user code, AI-generated code, or need isolated code execution environments. Covers the @deno/sandbox SDK.
4. [deno](https://skillsdocs.com/denoland/skills/deno.md) — Use when writing, running, configuring, reviewing, or debugging code in a Deno project, or when scaffolding a new one. Covers dependency management with deno i…
5. [migrate-to-deno](https://skillsdocs.com/denoland/skills/migrate-to-deno.md) — Use when moving a Node.js, npm, Yarn, pnpm, or Bun project to Deno, or when adopting Deno incrementally in an existing JavaScript or TypeScript codebase. Cover…


## Front matter

_The repository README, verbatim except that relative links are resolved against https://github.com/denoland/skills/blob/main/._

# Deno Development Skills

Modern Deno development knowledge for AI coding assistants. These skills teach
your AI assistant how to build Deno applications using current best practices.

## Skills

| Skill               | Description                                                                                     |
| ------------------- | ----------------------------------------------------------------------------------------------- |
| **deno**            | Core skill: dependency management, permissions, `deno.json`, the built-in toolchain, publishing |
| **migrate-to-deno** | Moving a Node, npm, Yarn, pnpm, or Bun project to Deno                                          |
| **deno-deploy**     | Deployment workflows for Deno Deploy                                                            |
| **deno-frontend**   | Fresh framework, Preact components, Tailwind CSS                                                |
| **deno-sandbox**    | Safe code execution with @deno/sandbox                                                          |

Targets Deno 2.9+.

### Changed in 2.0

`deno-guidance`, `deno-expert`, and `deno-project-templates` have been merged
into the single **deno** skill. Their content overlapped heavily, and project
scaffolding is now handled by `deno init` rather than by pasted templates. If
you installed any of the three individually, install `deno` instead.

## Key Principles

1. **Deno works like npm and bun** - `deno install` reads `package.json`,
   `deno add express` installs from npm, `node_modules` and `node:` built-ins
   work. Migration is not a rewrite.
2. **npm and JSR both work** - use whichever has the package you need; JSR is a
   good default for new Deno-first code and the standard library (`@std/*`).
3. **Built-in tools** - `deno fmt`, `deno lint`, `deno test`, `deno check`
   replace prettier, eslint, jest, and tsc with no dependencies.
4. **Permissions are the real difference** - prefer scoped grants like
   `--allow-net=example.com` over `-A`.

## Versioning

This project uses [Semantic Versioning](https://semver.org/). When contributing
changes:

### When to Bump Versions

| Change Type                       | Version Bump          | Example                                     |
| --------------------------------- | --------------------- | ------------------------------------------- |
| Breaking changes                  | MAJOR (1.0 → 2.0)     | Fundamentally altering how a skill works    |
| New features, significant updates | MINOR (1.1 → 1.2)     | Adding new guidance, updating documentation |
| Typo fixes, small clarifications  | PATCH (1.1.0 → 1.1.1) | Fixing formatting, correcting typos         |

### Files to Update

When making changes, update the appropriate version numbers:

1. **Skill-specific changes** - Update the skill's `version` in its `SKILL.md`
   frontmatter
2. **Plugin releases** - Update `version` in both:
   - `.claude-plugin/plugin.json`
   - `.claude-plugin/marketplace.json`

### For Contributors

- Include version bumps in your PRs when changing skill content
- Use [conventional commits](https://www.conventionalcommits.org/) (e.g.,
  `feat:`, `fix:`, `docs:`) to indicate change type
- When in doubt, bump the MINOR version for content changes

## Installation

These skills follow the
[Agent Skills Specification](https://agentskills.io/specification).

### Claude Code

**Option 1: Install as a plugin**

```bash
# Step 1: Add the marketplace
/plugin marketplace add denoland/skills

# Step 2: Install the plugin
/plugin install deno-skills@denoland-skills
```

**Option 2: `npx skills`**

Works across Claude Code, Cursor, Copilot, and other skills-compatible agents:

```bash
# All skills
npx skills add denoland/skills

# Or just one
npx skills add denoland/skills --skill deno
```

**Option 3: Manual installation**

Copy the skills you want to use:

```bash
# Clone the repository
git clone https://github.com/denoland/skills.git /tmp/deno-skills

# Copy individual skills to your personal skills directory
cp -r /tmp/deno-skills/skills/deno ~/.claude/skills/
cp -r /tmp/deno-skills/skills/deno-deploy ~/.claude/skills/
# ... or copy all skills
cp -r /tmp/deno-skills/skills/* ~/.claude/skills/

# Or for project-specific installation
cp -r /tmp/deno-skills/skills/* .claude/skills/
```

### Cursor

> Note: Agent Skills in Cursor are currently only available in v2.4+.

```bash
# Clone the repository
git clone https://github.com/denoland/skills.git /tmp/deno-skills

# Copy skills to your Cursor skills directory
cp -r /tmp/deno-skills/skills/* ~/.cursor/skills/

# Or for project-specific installation
cp -r /tmp/deno-skills/skills/* .cursor/skills/
```

### VS Code with GitHub Copilot

> Note: Agent Skills require the `chat.useAgentSkills` setting to be enabled
> (currently in preview).

```bash
# Clone the repository
git clone https://github.com/denoland/skills.git /tmp/deno-skills

# Copy skills to your project's skills directory
mkdir -p .github/skills
cp -r /tmp/deno-skills/skills/* .github/skills/

# Or for personal installation
cp -r /tmp/deno-skills/skills/* ~/.copilot/skills/
```

To enable Agent Skills in VS Code:

1. Open VS Code Settings (Cmd/Ctrl + ,)
2. Search for `chat.useAgentSkills`
3. Enable the setting

### Other Platforms

For other AI coding assistants that support the Agent Skills specification, copy
the skill directories from `skills/` to your platform's skills directory. Check
your platform's documentation for the correct location.

## Usage

Once installed, your AI assistant will automatically apply Deno best practices
when:

- Working in projects with a `deno.json` file
- Creating new Deno applications
- Adding dependencies
- Deploying to Deno Deploy
- Building Fresh web applications
- Running user code in sandboxes

## Documentation Resources

- [Deno Documentation](https://docs.deno.com)
- [Fresh Framework](https://fresh.deno.dev/docs)
- [JSR Package Registry](https://jsr.io)
- [Deno Deploy](https://docs.deno.com/deploy/)
- [Agent Skills Specification](https://agentskills.io/specification)

## License

MIT License - see [LICENSE](https://github.com/denoland/skills/blob/main/LICENSE)

---

<!-- chapter:begin slug=deno-deploy position=1 -->

## 1. deno-deploy

- **Source:** https://github.com/denoland/skills/blob/main/skills/deno-deploy/SKILL.md
- **Raw:** https://raw.githubusercontent.com/denoland/skills/main/skills/deno-deploy/SKILL.md
- **Markdown:** https://skillsdocs.com/denoland/skills/deno-deploy.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (8), referenced from this skill's directory:
  - `references/AUTHENTICATION.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/deno-deploy/references/AUTHENTICATION.md
  - `references/DATABASES.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/deno-deploy/references/DATABASES.md
  - `references/DENO_KV.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/deno-deploy/references/DENO_KV.md
  - `references/DOMAINS.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/deno-deploy/references/DOMAINS.md
  - `references/FRAMEWORKS.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/deno-deploy/references/FRAMEWORKS.md
  - `references/ORGANIZATIONS.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/deno-deploy/references/ORGANIZATIONS.md
  - `references/RUNTIME.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/deno-deploy/references/RUNTIME.md
  - `references/TROUBLESHOOTING.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/deno-deploy/references/TROUBLESHOOTING.md

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: deno-deploy
description: Use when deploying Deno apps to production, asking about Deno Deploy, or working with `deno deploy` CLI commands. Covers deployment workflows, environment variables, KV database access, custom domains, the --tunnel flag for local development, and the `deno deploy` command reference.
license: MIT
metadata:
  author: denoland
  version: "1.5"
---

# Deno Deploy

This skill provides guidance for deploying applications to Deno Deploy.

## Scope Boundaries

This skill applies **only** to Deno Deploy questions. Follow these rules:

- If the user asks about **AWS Lambda, Vercel, Netlify, Google Cloud Run,
  Docker, Kubernetes, or any other deployment platform**, answer using that
  platform directly. Do not mention Deno Deploy at all — not as an alternative,
  not as a comparison, not as a suggestion.
- If the user asks about **running a local Deno script** (not deploying), answer
  the local question directly. Do not mention Deno Deploy, deployment, or the
  `--tunnel` flag.
- Do not include `deno deploy` commands, Deno KV, or Deno Deploy environment
  variable configuration in responses about other platforms or local-only
  scripts.
- Only discuss Deno Deploy when the user explicitly asks about Deno Deploy or
  deploying a Deno application to production.

## Important: Use `deno deploy`, NOT `deployctl`

**Always use the `deno deploy` command.** Do NOT use `deployctl`.

- `deployctl` is for Deno Deploy Classic (deprecated)
- `deno deploy` is the modern, integrated command built into the Deno CLI
- **Requires Deno >= 2.4.2** - the `deno deploy` subcommand was introduced in
  Deno 2.4

## When Unsure About CLI Flags

**Always run `--help` before guessing at flags.** The `deno deploy` subcommand
has many flags, and they change between versions. When you're unsure what a
command accepts:

```bash
# See all subcommands
deno deploy --help

# See flags for a specific subcommand
deno deploy create --help
deno deploy env --help
deno deploy database --help
```

This takes seconds and prevents repeated trial-and-error failures. Never assume
a flag exists — check first.

## Deployment Workflow

**Always show the core deploy command first** — then explain diagnostic steps.
When a user asks "how do I deploy?", lead with the actual command
(`deno deploy --prod`) before covering pre-flight checks and configuration.

### Step 1: Locate the App Directory

Before running any deploy commands, find where the Deno app is located:

```bash
# Check if deno.json exists in current directory
if [ -f "deno.json" ] || [ -f "deno.jsonc" ]; then
  echo "APP_DIR: $(pwd)"
else
  # Look for deno.json in immediate subdirectories
  find . -maxdepth 2 -name "deno.json" -o -name "deno.jsonc" 2>/dev/null | head -5
fi
```

All deploy commands must run from the app directory.

### Step 2: Pre-Flight Checks

Check Deno version and existing configuration:

```bash
# Check Deno version (must be >= 2.4.2)
deno --version | head -1

# Check for existing deploy config
grep -E '"org"|"app"' deno.json deno.jsonc 2>/dev/null || echo "NO_DEPLOY_CONFIG"
```

### Step 3: Check for Startup Dependencies

Before deploying, check if the app connects to a database or external service at
startup (e.g., top-level `await initDb()` in `main.ts`). If it does, the deploy
will fail during warmup because the database doesn't exist yet.

**If the app has startup database dependencies, follow this order:**

1. **Create the app with `--no-wait`** so a warmup failure doesn't block you:
   ```bash
   deno deploy create \
     --org <ORG_NAME> --app <APP_NAME> \
     --source local --runtime-mode dynamic --entrypoint main.ts \
     --build-timeout 5 --build-memory-limit 1024 --region us \
     --no-wait
   ```

2. **Provision and assign the database:**
   ```bash
   deno deploy database provision my-db --kind prisma --region us-east-1
   deno deploy database assign my-db --app <APP_NAME>
   ```

3. **Redeploy** (now the database exists, warmup will succeed):
   ```bash
   deno deploy --prod
   ```

If the app has no startup dependencies, skip this step and deploy normally
below.

### Step 4: Deploy Based on Configuration

**If `deploy.org` AND `deploy.app` exist in deno.json:**

```bash
# Build if needed (Fresh, Astro, etc.)
deno task build

# Deploy to production
deno deploy --prod
```

**If NO deploy config exists:**

**Apps must be created before they can be deployed to.** You cannot run
`deno deploy --prod` until an app exists.

**IMPORTANT: Ask the user first** - Do they have an existing app on Deno Deploy,
or do they need to create a new one?

**If they have an existing app**, add the config directly to deno.json:

```json
{
  "deploy": {
    "org": "<ORG_NAME>",
    "app": "<APP_NAME>"
  }
}
```

The org name is in the Deno Deploy console URL (e.g.,
`console.deno.com/your-org-name`). Once this config is in place, subsequent
deploys just need `deno deploy --prod`.

**If they need to create a new app:**

The CLI needs an organization name. Find it at https://console.deno.com - the
org is in the URL path (e.g., `console.deno.com/your-org-name`).

**Interactive creation** (opens a browser — only works when a human is at the
keyboard):

```bash
deno deploy create --org <ORG_NAME>
# A browser window opens - complete the app creation there
```

**Non-interactive creation** (use when an AI agent is performing the deploy, or
in CI/CD):

```bash
deno deploy create \
  --org <ORG_NAME> \
  --app <APP_NAME> \
  --source local \
  --runtime-mode dynamic \
  --entrypoint main.ts \
  --build-timeout 5 \
  --build-memory-limit 1024 \
  --region us
```

The create command also does the initial deploy. After it completes, `deno.json`
is updated with `deploy.org` and `deploy.app` automatically. From that point on,
subsequent deploys only need:

```bash
deno deploy --prod
```

After completion, verify the config was saved:

```bash
grep -E '"org"|"app"' deno.json
```

**When an AI agent is performing the deployment**, always use the
non-interactive flow with explicit flags. The interactive flow requires browser
windows and terminal prompts that agents cannot navigate.

## Core Commands

### Production Deployment

```bash
deno deploy --prod
```

### Preview Deployment

```bash
deno deploy
```

Preview deployments create a unique URL for testing without affecting
production.

### Targeting Specific Apps

```bash
deno deploy --org my-org --app my-app --prod
```

### Configuring an Entrypoint

Set the entrypoint in your `deno.json` (this is used by `deno deploy create`
during app creation):

```json
{
  "deploy": {
    "entrypoint": "main.ts"
  }
}
```

Note: `--entrypoint` is a flag on `deno deploy create`, not on `deno deploy`
itself.

### Additional Flags

These flags are available on `deno deploy create` (and apply during the initial
deploy):

| Flag                   | Purpose                                  |
| ---------------------- | ---------------------------------------- |
| `--allow-node-modules` | Include node_modules directory in upload |
| `--no-wait`            | Skip waiting for the build to complete   |

## Creating Apps (Non-Interactive Reference)

When any flag beyond `--org` is provided, `deno deploy create` runs in
non-interactive mode — all required flags must be specified. This is the
recommended approach for AI agents and CI/CD pipelines.

### Required Flags

| Flag                        | Description                                           |
| --------------------------- | ----------------------------------------------------- |
| `--org <name>`              | Organization name                                     |
| `--app <name>`              | Application name (becomes your URL: `<app>.deno.dev`) |
| `--source <local\|github>`  | Deploy from local files or a GitHub repo              |
| `--build-timeout <minutes>` | Build timeout: 5, 10, 15, 20, 25, or 30               |
| `--build-memory-limit <MB>` | Memory limit: 1024, 2048, 3072, or 4096               |
| `--region <region>`         | Deployment region: us, eu, or global                  |

### GitHub Source Flags

When using `--source github`, you also need:

| Flag             | Description             |
| ---------------- | ----------------------- |
| `--owner <name>` | GitHub repository owner |
| `--repo <name>`  | GitHub repository name  |

### Build Configuration Flags

| Flag                                 | Description                                                   |
| ------------------------------------ | ------------------------------------------------------------- |
| `--app-directory <path>`             | Path to app directory (for monorepos)                         |
| `--framework-preset <preset>`        | Framework preset (see [Frameworks](references/FRAMEWORKS.md)) |
| `--install-command <cmd>`            | Custom install command                                        |
| `--build-command <cmd>`              | Custom build command                                          |
| `--pre-deploy-command <cmd>`         | Command to run before deploy                                  |
| `--do-not-use-detected-build-config` | Skip auto-detection of framework config                       |

The CLI auto-detects your framework and build configuration. If a framework is
detected, you can skip `--install-command`, `--build-command`,
`--pre-deploy-command`, and `--runtime-mode` — they'll be inferred from the
preset. Use `--do-not-use-detected-build-config` to override detection. **When
using this flag, all three build commands (`--install-command`,
`--build-command`, `--pre-deploy-command`) plus `--runtime-mode` become
required** — omitting any of them causes exit code 2.

### Runtime Mode Flags

You must pick a runtime mode with `--runtime-mode <dynamic|static>` (unless a
framework preset handles it).

**Dynamic mode** (for apps with a server):

| Flag                        | Description                                 |
| --------------------------- | ------------------------------------------- |
| `--entrypoint <path>`       | Entry file (required for dynamic mode)      |
| `--arguments <args>`        | Arguments passed to entrypoint (repeatable) |
| `--working-directory <cwd>` | Working directory for the process           |

**Static mode** (for static sites):

| Flag                 | Description                                         |
| -------------------- | --------------------------------------------------- |
| `--static-dir <dir>` | Directory to serve static files from (required)     |
| `--single-page-app`  | Serve index.html for routes that don't match a file |

### Other Flags

| Flag                   | Description                                           |
| ---------------------- | ----------------------------------------------------- |
| `--dry-run`            | Validate everything without actually creating the app |
| `--no-wait`            | Don't wait for the build to complete                  |
| `--allow-node-modules` | Include node_modules in the upload                    |

### Examples

**Simple Deno server:**

```bash
deno deploy create \
  --org my-org --app my-api \
  --source local \
  --runtime-mode dynamic --entrypoint main.ts \
  --build-timeout 5 --build-memory-limit 1024 --region us
```

**Fresh app (framework auto-detected):**

```bash
deno deploy create \
  --org my-org --app my-fresh-app \
  --source local \
  --build-timeout 5 --build-memory-limit 1024 --region us
```

**Next.js from GitHub:**

```bash
deno deploy create \
  --org my-org --app my-next-app \
  --source github --owner my-github-user --repo my-next-repo \
  --framework-preset Next \
  --build-timeout 15 --build-memory-limit 2048 --region us \
  --allow-node-modules
```

**Static site:**

```bash
deno deploy create \
  --org my-org --app my-static-site \
  --source local \
  --runtime-mode static --static-dir dist --single-page-app \
  --build-command "deno task build" \
  --build-timeout 5 --build-memory-limit 1024 --region us
```

## Environment Variables

### Contexts

Deno Deploy has three "contexts" - logical environments where your code runs,
each with its own set of variables:

| Context         | Purpose                                 |
| --------------- | --------------------------------------- |
| **Production**  | Live traffic on your production URL     |
| **Development** | Preview deployments and branch URLs     |
| **Build**       | Only available during the build process |

You can set different values for the same variable in each context. For example,
you might use a test database URL in Development and the real one in Production.

### Predefined Variables

These are automatically available in your code:

| Variable             | Description                            |
| -------------------- | -------------------------------------- |
| `DENO_DEPLOY`        | Always `1` when running on Deno Deploy |
| `DENO_DEPLOYMENT_ID` | Unique ID for the current deployment   |
| `DENO_DEPLOY_ORG_ID` | Your organization's ID                 |
| `DENO_DEPLOY_APP_ID` | Your application's ID                  |
| `CI`                 | Set to `1` during builds only          |

### Accessing Variables in Code

```typescript
const dbUrl = Deno.env.get("DATABASE_URL");
const isDenoDeploy = Deno.env.get("DENO_DEPLOY") === "1";
```

### Managing Variables via CLI

```bash
# Add a plain text variable
deno deploy env add DATABASE_URL "postgres://..."

# Add a secret variable (hidden after creation, only readable in code)
deno deploy env add API_KEY "sk-..." --secret

# List all variables
deno deploy env list

# Update just the value (keeps contexts and secret status)
deno deploy env update-value DATABASE_URL "postgres://new-url..."

# Update which contexts a variable applies to
deno deploy env update-contexts DATABASE_URL production development

# Delete a variable
deno deploy env delete DATABASE_URL

# Load from .env file (all values treated as secrets by default)
deno deploy env load .env.production

# Load from .env file, marking specific keys as non-secrets
deno deploy env load .env.production --non-secrets PUBLIC_URL APP_NAME
```

### Variable Types

- **Plain text** - Visible in the dashboard, good for feature flags and
  non-sensitive config
- **Secrets** - Hidden after creation, only readable in your code, use for API
  keys and credentials

### Limits

- Key names: max 128 bytes
- Values: max 16 KB
- Keys cannot start with `DENO_`, `LD_`, or `OTEL_`

## Viewing Logs

```bash
# Stream live logs
deno deploy logs

# Filter by date range
deno deploy logs --start 2026-01-15 --end 2026-01-16
```

## Databases & Storage

Deno Deploy provides built-in database support with **automatic environment
isolation**. Each environment (production, preview, branch) gets its own
isolated database automatically.

### Available Options

| Engine         | Use Case                                                 |
| -------------- | -------------------------------------------------------- |
| **Deno KV**    | Key-value storage, simple data, counters, sessions       |
| **PostgreSQL** | Relational data, complex queries, existing Postgres apps |

### Deno KV Quick Start

No configuration needed - just use the built-in API:

```typescript
const kv = await Deno.openKv();

// Store data
await kv.set(["users", "alice"], { name: "Alice", role: "admin" });

// Retrieve data
const user = await kv.get(["users", "alice"]);
console.log(user.value); // { name: "Alice", role: "admin" }

// List by prefix
for await (const entry of kv.list({ prefix: ["users"] })) {
  console.log(entry.key, entry.value);
}
```

Deno Deploy automatically connects to the correct database based on your
environment.

### PostgreSQL

For PostgreSQL, Deno Deploy injects environment variables (`DATABASE_URL`,
`PGHOST`, etc.) that most libraries detect automatically:

```typescript
// Recommended: npm:pg (best PostgreSQL driver for Deno Deploy)
import pg from "npm:pg";
const pool = new pg.Pool(); // Reads DATABASE_URL from environment automatically
```

### Provisioning

Use the `deno deploy database` command to provision and manage databases:

```bash
# Provision a Deno KV database
deno deploy database provision my-database --kind denokv

# Provision a Prisma PostgreSQL database
deno deploy database provision my-database --kind prisma --region us-east-1

# Assign to your app
deno deploy database assign my-database --app my-app
```

For detailed CLI commands, see [Databases](references/DATABASES.md).

### Local Development

Use `--tunnel` to connect to your hosted development database locally:

```bash
deno task --tunnel dev
```

See [Databases](references/DATABASES.md) and [Deno KV](references/DENO_KV.md)
for detailed documentation.

## Local Development Tunnel

The tunnel feature lets you expose your local development server to the
internet. This is useful for:

- **Testing webhooks** - Receive webhook callbacks from external services
- **Sharing with teammates** - Let others preview your local work
- **Mobile testing** - Access your local server from other devices

### Basic Usage

Add the `--tunnel` flag when running your app:

```bash
deno run --tunnel -A main.ts
```

The first time you run this, it will:

1. Ask you to authenticate with Deno Deploy (opens a browser)
2. Ask you to select which app to connect the tunnel to
3. Generate a public URL that forwards requests to your local server

### Using with Tasks

You can use `--tunnel` with your existing tasks in `deno.json`:

```bash
deno task --tunnel dev
```

This runs your `dev` task with the tunnel enabled.

### What the Tunnel Provides

Beyond just forwarding requests, the tunnel also:

- **Syncs environment variables** - Variables set in your Deno Deploy app's
  "Local" context become available to your local process
- **Sends logs and metrics** - OpenTelemetry data goes to the Deno Deploy
  dashboard (filter with `context:local`)
- **Connects to databases** - Automatically connects to your assigned local
  development databases

### Managing Tunnels

- View active tunnels in the Deno Deploy dashboard under the "Tunnels" tab
- Stop a tunnel by terminating the Deno process (Ctrl+C)

## Command Reference

| Command                                               | Purpose                                                |
| ----------------------------------------------------- | ------------------------------------------------------ |
| `deno deploy --prod`                                  | Deploy to production (app must exist first)            |
| `deno deploy`                                         | Preview deployment                                     |
| `deno deploy create --org <name>`                     | Create new app (interactive)                           |
| `deno deploy create --org <name> --app <name> ...`    | Create new app (non-interactive, see full flags above) |
| `deno deploy create ... --no-wait`                    | Create app without waiting for build to complete       |
| `deno deploy create ... --allow-node-modules`         | Create app including node_modules                      |
| `deno deploy env add <var> <value>`                   | Add plain text environment variable                    |
| `deno deploy env add <var> <value> --secret`          | Add secret environment variable                        |
| `deno deploy env list`                                | List environment variables                             |
| `deno deploy env update-value <var> <value>`          | Update variable value (keeps contexts/secret status)   |
| `deno deploy env update-contexts <var> <contexts...>` | Update which contexts a variable applies to            |
| `deno deploy env delete <var>`                        | Delete environment variable                            |
| `deno deploy env load <file>`                         | Load variables from .env file (defaults to secret)     |
| `deno deploy env load <file> --non-secrets <keys...>` | Load .env file, marking specific keys as non-secrets   |
| `deno deploy database provision <name> --kind <type>` | Provision a new database                               |
| `deno deploy database assign <name> --app <app>`      | Assign database to an app                              |
| `deno deploy logs`                                    | View deployment logs                                   |
| `deno run --tunnel -A <file>`                         | Start local tunnel                                     |
| `deno task --tunnel <task>`                           | Run task with tunnel                                   |

## Edge Runtime Notes

Deno Deploy runs in one or many regions (globally distributed). Keep in mind:

- **Environment variables** - Must be set via `deno deploy env`, not .env files
  at runtime
- **Global distribution** - Code runs at the region closest to users
- **Cold starts** - First request after idle may be slightly slower

## Additional References

- [Authentication](references/AUTHENTICATION.md) - Interactive and CI/CD
  authentication
- [Databases](references/DATABASES.md) - Database provisioning and connections
- [Deno KV](references/DENO_KV.md) - Key-value storage API and examples
- [Domains](references/DOMAINS.md) - Custom domains and SSL certificates
- [Frameworks](references/FRAMEWORKS.md) - Framework-specific deployment guides
- [Organizations](references/ORGANIZATIONS.md) - Managing orgs and members
- [Runtime](references/RUNTIME.md) - Lifecycle, cold starts, and limitations
- [Troubleshooting](references/TROUBLESHOOTING.md) - Common issues and solutions

## Documentation

- Official docs: https://docs.deno.com/deploy/
- CLI reference: https://docs.deno.com/runtime/reference/cli/deploy/
- Databases: https://docs.deno.com/deploy/reference/databases/
- Deno KV: https://docs.deno.com/deploy/reference/deno_kv/
- Domains: https://docs.deno.com/deploy/reference/domains/
- Environment variables & contexts:
  https://docs.deno.com/deploy/reference/env_vars_and_contexts/
- Organizations: https://docs.deno.com/deploy/reference/organizations/
- Runtime: https://docs.deno.com/deploy/reference/runtime/
- Tunnel: https://docs.deno.com/deploy/reference/tunnel/

<!-- chapter:end slug=deno-deploy -->

---

<!-- chapter:begin slug=deno-frontend position=2 -->

## 2. deno-frontend

- **Source:** https://github.com/denoland/skills/blob/main/skills/deno-frontend/SKILL.md
- **Raw:** https://raw.githubusercontent.com/denoland/skills/main/skills/deno-frontend/SKILL.md
- **Markdown:** https://skillsdocs.com/denoland/skills/deno-frontend.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (2), referenced from this skill's directory:
  - `references/FRESH_MIGRATION.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/deno-frontend/references/FRESH_MIGRATION.md
  - `references/FRESH.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/deno-frontend/references/FRESH.md

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: deno-frontend
description: Use when building a web frontend with Deno — running React, Vite, Astro, SvelteKit, Next.js, Nuxt or other npm frameworks under Deno, or working with Fresh, Deno's own island-architecture framework. Covers which path to pick, Fresh 2.x routes, handlers, islands, Preact signals, Tailwind, and Fresh 1.x to 2.x migration.
license: MIT
metadata:
  author: denoland
  version: "3.0"
---

# Frontend development with Deno

Two paths. Pick by what the project already uses.

## Regular npm frameworks — the usual choice

Deno runs the normal frontend ecosystem: React, Vue, Svelte, Solid, Vite, Astro,
Next.js, Nuxt, SvelteKit, Remix, SolidStart. Nothing needs to be ported, and
there is no Deno-specific way to write them.

```bash
deno create vite my-app     # or astro, next, nuxt, svelte…
cd my-app
deno install
deno task dev
```

`deno create` is `npm create`. `deno install` reads `package.json`.
`deno task <script>` runs `package.json` scripts. That is the whole difference.

**Follow the framework's own documentation for everything else** — routing,
components, data loading, and config are the framework's concern, not Deno's.
Don't invent Deno-flavoured variants of their APIs, and don't reach for Fresh
patterns in a React or Svelte project.

The only things worth knowing:

- Some frameworks need `"nodeModulesDir": "auto"` in `deno.json`; Next.js does.
- Permissions apply to the dev server too — framework tasks generally want `-A`.
- Deploying: see the `deno-deploy` skill, which lists per-framework build
  commands and presets.

## Fresh — Deno's own framework

Fresh suits a new Deno-first project that wants server rendering with minimal
client JavaScript. It uses **island architecture**: pages render on the server,
and only components in `islands/` ship JavaScript.

```bash
deno run -Ar jsr:@fresh/init
cd my-project
deno task dev                # http://localhost:5173
```

A Fresh project is Vite-based: `vite.config.ts` for the build, `main.ts` for the
server, file-based routes in `routes/`, islands in `islands/`, server-only
components in `components/`. Preact supplies the component model, with signals
for state.

```tsx
// islands/Counter.tsx — interactive, ships JS
import { useSignal } from "@preact/signals";

export default function Counter() {
  const count = useSignal(0);
  return <button onClick={() => count.value++}>Count: {count.value}</button>;
}
```

Three rules carry most of the weight:

1. Islands ship JavaScript — keep them small, leave everything else in
   `components/`.
2. Island props must be serializable. Functions cannot be passed.
3. Handlers take a single `(ctx)` parameter.

Load `references/FRESH.md` for routes, handlers, `define` helpers, middleware,
islands, signals, and Tailwind.

Use **Fresh 2.x**, imported from `"fresh"`. For an existing 1.x project, or one
pinned to a `2.0.0-alpha.*` release, see `references/FRESH_MIGRATION.md`.

## Further reading

- <https://fresh.deno.dev/docs> — Fresh documentation
- `references/FRESH.md` — Fresh 2.x patterns in depth
- `references/FRESH_MIGRATION.md` — Fresh 1.x and alpha migration

<!-- chapter:end slug=deno-frontend -->

---

<!-- chapter:begin slug=deno-sandbox position=3 -->

## 3. deno-sandbox

- **Source:** https://github.com/denoland/skills/blob/main/skills/deno-sandbox/SKILL.md
- **Raw:** https://raw.githubusercontent.com/denoland/skills/main/skills/deno-sandbox/SKILL.md
- **Markdown:** https://skillsdocs.com/denoland/skills/deno-sandbox.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: deno-sandbox
description: Use when building features that execute untrusted user code, AI-generated code, or need isolated code execution environments. Covers the @deno/sandbox SDK.
license: MIT
metadata:
  author: denoland
  version: "1.1"
---

# Deno Sandboxes

## Overview

Deno Sandboxes provide secure, isolated environments for running untrusted code.
Each sandbox runs in its own Linux microVM (using Firecracker, the same
technology as AWS Lambda) with a separate filesystem, network, and process
space. This makes them ideal for code playgrounds, AI agent tool execution, and
multi-tenant applications.

Reference: https://deno.com/deploy/sandboxes

## When to Use Sandboxes

Use Deno Sandboxes when you need to:

- Run user-submitted code safely
- Execute AI-generated code
- Build code playground platforms
- Create multi-tenant code execution environments
- Run automated tests in isolation

## Scope Boundaries

This skill applies **only** to Deno Sandbox (`@deno/sandbox`) questions. Follow
these rules:

- If the user asks about **Docker containers, Node.js vm2/vm, Web Workers, AWS
  Lambda isolation, or any other isolation technology**, answer using that
  technology directly. Do not suggest Deno Sandboxes as an alternative.
- Do not include `@deno/sandbox` imports, `Sandbox.create()`, or
  `sandbox.spawn()` in responses about other isolation technologies.
- Only recommend Deno Sandboxes when the user explicitly asks about them or is
  building code execution features in a Deno project.

## Getting Started

### Installation

```bash
deno add jsr:@deno/sandbox
```

### Basic Usage

```typescript
import { Sandbox } from "@deno/sandbox";

// Create a sandbox (auto-disposed when scope ends)
await using sandbox = await Sandbox.create();

// Run a command
const child = await sandbox.spawn("echo", { args: ["Hello from sandbox!"] });
const output = await child.output();

console.log(new TextDecoder().decode(output.stdout));
// Output: Hello from sandbox!
```

## Core Concepts

### Sandbox Lifecycle

Sandboxes are resources that must be disposed when done. **Always** use
`await using` for automatic cleanup:

```typescript
await using sandbox = await Sandbox.create();
// Sandbox is automatically destroyed when this scope ends
```

CRITICAL: Never show `const sandbox = await Sandbox.create()` without
`await using`. Always use the `await using` pattern for sandbox creation. Do not
show manual disposal alternatives.

### Running Processes

The `spawn` method runs commands inside the sandbox:

```typescript
const child = await sandbox.spawn("deno", {
  args: ["run", "script.ts"],
  stdin: "piped", // Enable stdin
  stdout: "piped", // Capture stdout
  stderr: "piped", // Capture stderr
});

// Wait for completion and get output
const output = await child.output();
console.log("Exit code:", output.code);
console.log("Stdout:", new TextDecoder().decode(output.stdout));
console.log("Stderr:", new TextDecoder().decode(output.stderr));
```

### Streaming I/O

For interactive processes or long-running commands:

```typescript
const child = await sandbox.spawn("deno", {
  args: ["repl"],
  stdin: "piped",
  stdout: "piped",
});

// Write to stdin
const writer = child.stdin!.getWriter();
await writer.write(new TextEncoder().encode("console.log('Hello')\n"));
await writer.close();

// Read from stdout
const reader = child.stdout!.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  console.log(new TextDecoder().decode(value));
}
```

### Killing Processes

```typescript
const child = await sandbox.spawn("sleep", { args: ["60"] });

// Kill with SIGTERM (default)
await child.kill();

// Or with specific signal
await child.kill("SIGKILL");

// Wait for exit
const status = await child.status;
console.log("Exited with signal:", status.signal);
```

## Common Patterns

### Running User Code Safely

```typescript
import { Sandbox } from "@deno/sandbox";

async function runUserCode(code: string): Promise<string> {
  await using sandbox = await Sandbox.create();

  // Write user code to a file in the sandbox
  await sandbox.fs.writeFile("/tmp/user_code.ts", code);

  // Run with restricted permissions
  const child = await sandbox.spawn("deno", {
    args: [
      "run",
      "--allow-none", // No permissions
      "/tmp/user_code.ts",
    ],
    stdout: "piped",
    stderr: "piped",
  });

  const output = await child.output();

  if (output.code !== 0) {
    throw new Error(new TextDecoder().decode(output.stderr));
  }

  return new TextDecoder().decode(output.stdout);
}
```

### Code Playground

```typescript
import { Sandbox } from "@deno/sandbox";

interface ExecutionResult {
  success: boolean;
  output: string;
  error?: string;
  executionTime: number;
}

async function executePlayground(code: string): Promise<ExecutionResult> {
  const start = performance.now();

  await using sandbox = await Sandbox.create();

  await sandbox.fs.writeFile("/playground/main.ts", code);

  const child = await sandbox.spawn("deno", {
    args: ["run", "--allow-net", "/playground/main.ts"],
    stdout: "piped",
    stderr: "piped",
  });

  const output = await child.output();
  const executionTime = performance.now() - start;

  return {
    success: output.code === 0,
    output: new TextDecoder().decode(output.stdout),
    error: output.code !== 0
      ? new TextDecoder().decode(output.stderr)
      : undefined,
    executionTime,
  };
}
```

### AI Agent Tool Execution

```typescript
import { Sandbox } from "@deno/sandbox";

async function executeAgentTool(
  toolCode: string,
  input: unknown,
): Promise<unknown> {
  await using sandbox = await Sandbox.create();

  // Create a wrapper that handles input/output
  const wrapper = `
    const input = ${JSON.stringify(input)};
    const tool = await import("/tool.ts");
    const result = await tool.default(input);
    console.log(JSON.stringify(result));
  `;

  await sandbox.fs.writeFile("/tool.ts", toolCode);
  await sandbox.fs.writeFile("/run.ts", wrapper);

  const child = await sandbox.spawn("deno", {
    args: ["run", "--allow-net", "/run.ts"],
    stdout: "piped",
    stderr: "piped",
  });

  const output = await child.output();

  if (output.code !== 0) {
    throw new Error(new TextDecoder().decode(output.stderr));
  }

  return JSON.parse(new TextDecoder().decode(output.stdout));
}
```

## Sandbox Features

### Resource Configuration

Sandboxes have configurable resources:

- **Default:** 2 vCPUs, 512MB memory, 10GB disk
- Startup time: Under 200ms

### What's Included

Each sandbox comes with:

- TypeScript/JavaScript runtime (Deno)
- Full Linux environment
- Network access (can be restricted)
- Temporary filesystem

### Security Features

- **Firecracker microVMs** - Same technology as AWS Lambda
- **Full isolation** - Separate kernel, filesystem, network
- **No data leakage** - Sandboxes can't access host system
- **Enforced policies** - Control outbound connections

## Deploying Sandboxes

Sandboxes can be deployed directly to Deno Deploy:

```bash
deno deploy --prod
```

The sandbox SDK works seamlessly in the Deno Deploy environment.

## API Reference

For the complete API, run:

```bash
deno doc jsr:@deno/sandbox
```

Key classes:

- `Sandbox` - Main class for creating/managing sandboxes
- `ChildProcess` - Represents a running process
- `Client` - For managing Deploy resources (apps, volumes)

## Quick Reference

| Task           | Code                                           |
| -------------- | ---------------------------------------------- |
| Create sandbox | `await using sandbox = await Sandbox.create()` |
| Run command    | `sandbox.spawn("cmd", { args: [...] })`        |
| Get output     | `const output = await child.output()`          |
| Write file     | `await sandbox.fs.writeFile(path, content)`    |
| Read file      | `await sandbox.fs.readFile(path)`              |
| Kill process   | `await child.kill()`                           |
| Check status   | `const status = await child.status`            |

## Common Mistakes

**Forgetting automatic disposal**

```typescript
// ❌ Wrong - always use "await using" for sandbox creation
// Never write: const sandbox = await Sandbox.create() without "await using"

// ✅ Correct - use "await using" for automatic cleanup
await using sandbox = await Sandbox.create();
await sandbox.spawn("echo", { args: ["hello"] });
// sandbox automatically disposed when scope ends
```

**Giving user code too many permissions**

```typescript
// ❌ Wrong - gives untrusted code full access
const child = await sandbox.spawn("deno", {
  args: ["run", "--allow-all", "/tmp/user_code.ts"],
});

// ✅ Correct - restrict permissions to what's needed
const child = await sandbox.spawn("deno", {
  args: ["run", "--allow-none", "/tmp/user_code.ts"], // No permissions
});

// Or if network is truly needed:
const child = await sandbox.spawn("deno", {
  args: ["run", "--allow-net", "/tmp/user_code.ts"], // Only network
});
```

**Not handling process output properly**

```typescript
// ❌ Wrong - forgetting to pipe stdout/stderr
const child = await sandbox.spawn("deno", { args: ["run", "script.ts"] });
const output = await child.output();
// output.stdout is empty because we didn't pipe it!

// ✅ Correct - pipe the streams you need
const child = await sandbox.spawn("deno", {
  args: ["run", "script.ts"],
  stdout: "piped",
  stderr: "piped",
});
const output = await child.output();
console.log(new TextDecoder().decode(output.stdout));
```

**Not setting timeouts for user code execution**

```typescript
// ❌ Wrong - user code could run forever
const child = await sandbox.spawn("deno", {
  args: ["run", "/tmp/user_code.ts"],
});
await child.output(); // Could hang indefinitely

// ✅ Correct - implement timeout handling
const child = await sandbox.spawn("deno", {
  args: ["run", "/tmp/user_code.ts"],
  stdout: "piped",
  stderr: "piped",
});

// Set a timeout to kill the process
const timeoutId = setTimeout(() => child.kill(), 5000); // 5 second limit

try {
  const output = await child.output();
  return output;
} finally {
  clearTimeout(timeoutId);
}
```

**Trusting sandbox output without validation**

```typescript
// ❌ Wrong - directly using untrusted output as code
const result = await runUserCode(code);
// Never execute or inject untrusted output!

// ✅ Correct - validate and sanitize output
const result = await runUserCode(code);
try {
  const parsed = JSON.parse(result); // Parse as data, not code
  if (isValidResponse(parsed)) {
    return parsed;
  }
} catch {
  throw new Error("Invalid response from sandbox");
}
```

<!-- chapter:end slug=deno-sandbox -->

---

<!-- chapter:begin slug=deno position=4 -->

## 4. deno

- **Source:** https://github.com/denoland/skills/blob/main/skills/deno/SKILL.md
- **Raw:** https://raw.githubusercontent.com/denoland/skills/main/skills/deno/SKILL.md
- **Markdown:** https://skillsdocs.com/denoland/skills/deno.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (1), referenced from this skill's directory:
  - `references/CLI.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/deno/references/CLI.md

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: deno
description: Use when writing, running, configuring, reviewing, or debugging code in a Deno project, or when scaffolding a new one. Covers dependency management with deno install and deno add, package.json and node_modules support, npm and JSR packages, permissions, where configuration belongs across package.json, tsconfig.json and deno.json, workspaces, the built-in toolchain (fmt, lint, test, check, bench, compile), and publishing.
license: MIT
metadata:
  author: denoland
  version: "1.0"
---

# Deno

A JavaScript and TypeScript runtime with a package manager, formatter, linter,
test runner, type checker, and bundler in one binary. Runs TypeScript directly.

Needs Deno 2.9+. Check with `deno --version`, update with `deno upgrade`.

## Deno works the way npm and bun do

Deno is not a separate ecosystem to port code into:

- `deno install` reads an existing `package.json` and writes a real
  `node_modules`.
- `deno add express` installs from **npm**. Unprefixed names default to npm.
- `deno task build` runs `scripts.build` from `package.json` or `tasks.build`
  from `deno.json`. If both define it, `deno.json` wins.
- Node built-ins work prefixed or not: `node:fs` and `fs` both resolve.
- `deno main.js` runs a file. `deno run` is optional.
- Deno reads `tsconfig.json`.

Don't tell users to rewrite imports, adopt JSR, or restructure as a
precondition. The two real differences are **permissions** and **npm lifecycle
scripts not running by default**.

Single-file scripts need no build step and no `tsconfig.json`. Applications and
framework projects keep their normal setup.

To convert an existing project, see the `migrate-to-deno` skill.

## Dependency management

```bash
deno install                  # install everything declared
deno add express              # from npm (unprefixed = npm)
deno add jsr:@std/path        # from JSR
deno add -D vitest            # dev dependency (package.json only)
deno remove express
deno outdated                 # list outdated deps
deno update                   # alias for `deno outdated --update`
deno update --latest          # ignore existing semver ranges
deno list                     # declared deps + resolved versions (npm ls)
deno why express              # why a package is in the tree
deno audit                    # vulnerability audit
deno ci                       # clean reproducible install for CI
dx cowsay hello               # run a package binary without installing (npx)
```

`deno ci` is the CI command, not `deno install`: it requires `deno.lock`,
deletes `node_modules`, installs strictly from the lockfile, and fails if the
lockfile is stale. `--prod` skips devDependencies.

`dx` is `npx` / `bunx` / `pnpm dlx`, and an alias for `deno x`. It runs **with
the sandbox disabled**, so treat it with the same care as `npx`.

Deno won't install a version published less than a day ago, limiting the window
for a compromised release. Override with `--min-dep-age`, which takes minutes
(`120`), an ISO-8601 duration (`P7D`), a cutoff date, or `0` to disable:

```bash
deno add --min-dep-age=0 npm:some-package
```

Lifecycle scripts (`postinstall`) don't run by default — a common surprise when
a native addon looks broken after install. Approve once per project:

```bash
deno approve-scripts                              # interactive picker
deno install --allow-scripts=npm:better-sqlite3
```

### Where configuration goes

| File            | Holds                                         |
| --------------- | --------------------------------------------- |
| `package.json`  | dependencies, scripts                         |
| `tsconfig.json` | TypeScript compiler options                   |
| `deno.json`     | Deno config: `fmt`, `lint`, tasks, workspaces |

**Put dependencies in `package.json`** — every other tool reads it, and Deno
resolves it natively. Use `deno.json` for dependencies only when there is no
`package.json`: a standalone script, or a JSR package. Likewise prefer
`tsconfig.json` over `compilerOptions` in `deno.json`, so `tsc` and editors see
the same settings.

Commit `deno.lock`. Deno seeds it from an existing `package-lock.json`,
`yarn.lock`, `bun.lock`, or pnpm lockfile, preserving pins.

### node_modules layout

Deno uses pnpm's isolated layout: real files in `node_modules/.deno/`, exposed
by symlinks, so a package can't import what it never declared. For a tool that
needs npm's flat hoisted tree:

```json
{ "nodeModulesLinker": "hoisted" }
```

`nodeModulesDir` applies only to projects without a `package.json`, so it is
rarely the right knob.

## Permissions

Deno grants no filesystem, network, environment, or subprocess access unless
asked.

```bash
deno run --allow-net=api.example.com --allow-read=./data main.ts
deno run -A main.ts          # allow everything
```

| Flag                     | Short | Grants                      |
| ------------------------ | ----- | --------------------------- |
| `--allow-read[=paths]`   | `-R`  | filesystem read             |
| `--allow-write[=paths]`  | `-W`  | filesystem write            |
| `--allow-net[=hosts]`    | `-N`  | network                     |
| `--allow-env[=names]`    | `-E`  | environment variables       |
| `--allow-sys[=apis]`     | `-S`  | OS information              |
| `--allow-import[=hosts]` | `-I`  | imports from remote hosts   |
| `--allow-run[=bins]`     | —     | subprocesses                |
| `--allow-ffi[=paths]`    | —     | native libraries (unstable) |
| `--allow-all`            | `-A`  | everything                  |

`-S` is `--allow-sys`, not `--allow-run`. Every flag takes an allowlist —
`--allow-net=example.com:443` beats bare `--allow-net`. Matching `--deny-*`
flags always win.

On `Requires net access to "..."`, add that specific permission. `-A` is fine
for trusted first-party code and during migration, but a poor default to commit
in a task.

## Configuration

`deno.json` (or `.jsonc`) is auto-discovered from the current directory upward.

```json
{
  "tasks": {
    "dev": "deno watch -A main.ts",
    "start": "deno run -A main.ts"
  },
  "fmt": { "exclude": ["build/"] },
  "lint": { "rules": { "exclude": ["no-explicit-any"] } },
  "exclude": ["build/", "dist/"]
}
```

Top-level `exclude` applies to every subcommand; per-tool `exclude` narrows it.

`deno.json` also accepts `imports`, an import map pointing bare specifiers at
real ones. That is how a project without `package.json` declares dependencies,
and how a JSR package declares its own alongside `name`, `version`, `exports`.

### Workspaces

npm, Yarn, and Bun workspaces work out of the box — Deno reads `package.json`
`"workspaces"` directly. pnpm is the exception: `pnpm-workspace.yaml` is
migrated into `deno.json` on first run, which must then be re-run.

```json
{ "workspace": ["./packages/core", "./packages/cli"] }
```

Members are explicit or single-level globs (`"packages/*"`); `**` and negation
are unsupported. Run a task across members with `deno task --filter '*' build`.

## Packages: npm and JSR

**Prefer npm** — it is where the ecosystem is, and `deno add express` is the
normal case. Reach for JSR for the standard library (`@std/*`), or to publish
TypeScript that consumers get types for without a build step. Mixing is fine.

```bash
deno add jsr:@std/path npm:express
deno doc jsr:@std/path        # read a package's API from the terminal
```

Deno once used full URL imports (`https://deno.land/x/...`). They still run but
aren't recommended; to modernize, `deno add` the package and import the bare
specifier.

## Built-in tooling

```bash
deno fmt              # format (--check for CI)
deno lint             # lint (--fix, --rules)
deno test             # tests (--watch, --parallel, --coverage=dir)
deno check main.ts    # type-check without running
deno bench            # benchmarks
deno coverage         # coverage report from --coverage output
deno compile main.ts  # single-file executable (--target cross-compiles)
deno doc mod.ts       # docs (--html for a site)
deno info main.ts     # module graph and cache info
```

These cover prettier, eslint, jest/vitest, tsc, and pkg/nexe with no config or
dependencies — but they are **not** drop-in replacements. Parity is incomplete,
so moving an established project is real work. **There is no need to migrate:**
keep prettier, eslint, and vitest, and use Deno as runtime and package manager.
Prefer the built-in tools for new projects.

Suppress with `// deno-lint-ignore <rule>`, `// deno-lint-ignore-file`,
`// deno-fmt-ignore`, `// deno-fmt-ignore-file`. In Markdown,
`<!-- deno-fmt-ignore -->` before a code block protects illustrative snippets
that aren't valid standalone code.

## Running code

```bash
deno main.ts                 # deno run is optional
deno watch main.ts           # reload on change (replaces nodemon)
deno task dev                # task from package.json or deno.json
deno repl
deno eval "console.log(1)"
```

`deno watch` hot-replaces modules, restarting if that fails; it aliases
`deno run --watch-hmr`.

An HTTP server needs no dependencies:

```ts
Deno.serve((_req) => new Response("Hello"));
```

## Starting a new project

Scaffold rather than hand-writing the files:

```bash
deno init my-project          # script + test + deno.json
deno init --empty my-project  # just main.ts and deno.json
deno init --lib my-lib        # library laid out for JSR
deno create vite my-app       # scaffold from a package initializer
```

`deno create` is `npm create` / `yarn create` and covers that ecosystem
(`deno create astro`, etc). Unprefixed names are npm; `--jsr` selects JSR.

## Publishing

**To npm the regular flow still works** — `npm publish`, or `deno pack` to build
the tarball first. `deno publish` targets JSR only, from a `deno.json` with
`name`, `version`, and `exports`:

```bash
deno publish --dry-run
deno publish
```

Provenance attestation is automatic on GitHub Actions. `deno bump-version patch`
bumps the version, across every member at a workspace root.

Guide: <https://docs.deno.com/runtime/reference/cli/publish/>

## Reviewing Deno code

- `-A` committed in a task where a scoped grant would work.
- `deno.lock` uncommitted, or CI running `deno install` instead of `deno ci`.
- Inline `jsr:`/`npm:` specifiers in a project with a `package.json` — use
  `deno add` so the version lives in one place. Fine in standalone scripts.
- A specifier with no version constraint.
- Dependencies or compiler options in `deno.json` when `package.json` or
  `tsconfig.json` exists.
- Missing `deno fmt --check`, `deno lint`, `deno check` in CI.

## Further reading

- <https://docs.deno.com> — runtime documentation
- <https://docs.deno.com/api/> — `Deno.*` API reference
- `references/CLI.md` — fuller subcommand and flag reference
- `deno <subcommand> --help` — authoritative and version-accurate; check it
  before guessing at a flag.

<!-- chapter:end slug=deno -->

---

<!-- chapter:begin slug=migrate-to-deno position=5 -->

## 5. migrate-to-deno

- **Source:** https://github.com/denoland/skills/blob/main/skills/migrate-to-deno/SKILL.md
- **Raw:** https://raw.githubusercontent.com/denoland/skills/main/skills/migrate-to-deno/SKILL.md
- **Markdown:** https://skillsdocs.com/denoland/skills/migrate-to-deno.md
- **Licence:** MIT — https://spdx.org/licenses/MIT.html

Bundled files (5), referenced from this skill's directory:
  - `references/FROM_BUN.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/migrate-to-deno/references/FROM_BUN.md
  - `references/FROM_NPM.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/migrate-to-deno/references/FROM_NPM.md
  - `references/FROM_PNPM.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/migrate-to-deno/references/FROM_PNPM.md
  - `references/FROM_YARN.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/migrate-to-deno/references/FROM_YARN.md
  - `references/NODE_APIS.md` — https://raw.githubusercontent.com/denoland/skills/main/skills/migrate-to-deno/references/NODE_APIS.md

<!-- Verbatim upstream SKILL.md follows, YAML frontmatter included. -->

---
name: migrate-to-deno
description: Use when moving a Node.js, npm, Yarn, pnpm, or Bun project to Deno, or when adopting Deno incrementally in an existing JavaScript or TypeScript codebase. Covers using Deno as a drop-in package manager, running existing package.json scripts, CommonJS versus ESM, node_modules layout, lockfile migration, permissions, whether to adopt the built-in toolchain, and per-tool command equivalents.
license: MIT
metadata:
  author: denoland
  version: "1.0"
---

# Migrating to Deno

Requires Deno 2.9 or later. For general Deno usage once migrated, see the `deno`
skill.

## Most Node projects already run under Deno

Deno reads an existing `package.json`, resolves the same npm packages, writes a
real `node_modules`, runs the same scripts, and supports `node:` built-ins.
TypeScript runs with no build step.

There is usually **no code to change** — only which binary you invoke. Don't
start by rewriting imports to `jsr:`, swapping dependencies for Deno-specific
ones, or restructuring directories. Proposing that is the most common way this
goes wrong.

## Migrate in rungs

Each rung is independently useful and reversible. Stop wherever suits the
project; plenty of teams stop at rung 1.

### Rung 1 — Deno as the package manager only

```bash
deno install
```

Reads `package.json`, resolves the same dependencies, writes `node_modules`, and
creates `deno.lock` — seeded from any existing `package-lock.json`, `yarn.lock`,
`bun.lock`, or pnpm lockfile, so pins and integrity hashes carry over instead of
drifting.

The app still runs under `node`; teammates are unaffected. Commit `deno.lock`
once verified. **To back out:** delete `deno.lock` and `node_modules`, then
`npm install`.

### Rung 2 — Run it with Deno

```bash
deno run -A main.js      # or: deno -A main.js
deno task build          # runs scripts.build from package.json
```

Use `-A` here. The goal is confirming the program works, not designing a
permission policy — changing both at once makes failures ambiguous.

### Rung 3 — Tighten permissions

Replace `-A` with the narrowest set that works: run it, read what it asks for,
grant exactly that.

```bash
deno run --allow-net=api.example.com --allow-read=./config --allow-env=PORT main.js
```

This buys something Node cannot offer, and is worth doing before deploying.

### Rung 4 — Optionally, adopt the built-in toolchain

`deno fmt` for prettier, `deno lint` for eslint, `deno test` for jest or vitest,
`deno check` for tsc, `deno watch` for nodemon, `deno compile` for pkg.

**Optional, and usually not worth it for an existing project.** These are not
drop-in replacements; parity is incomplete, so this is a real migration, not a
config change. A project happy with prettier, eslint, and vitest should keep
them and use Deno as runtime and package manager only. Prefer the built-in tools
for new projects. If you do move an existing one, go a tool at a time.

## Command equivalents

| Task          | npm                 | Yarn                        | pnpm                       | Bun                             | Deno              |
| ------------- | ------------------- | --------------------------- | -------------------------- | ------------------------------- | ----------------- |
| Install all   | `npm install`       | `yarn install`              | `pnpm install`             | `bun install`                   | `deno install`    |
| Add           | `npm i <p>`         | `yarn add <p>`              | `pnpm add <p>`             | `bun add <p>`                   | `deno add <p>`    |
| Add dev       | `npm i -D <p>`      | `yarn add -D <p>`           | `pnpm add -D <p>`          | `bun add -d <p>`                | `deno add -D <p>` |
| Remove        | `npm uninstall <p>` | `yarn remove <p>`           | `pnpm remove <p>`          | `bun remove <p>`                | `deno remove <p>` |
| CI install    | `npm ci`            | `yarn install --immutable`† | `pnpm i --frozen-lockfile` | `bun install --frozen-lockfile` | `deno ci`         |
| Run script    | `npm run <s>`       | `yarn <s>`                  | `pnpm <s>`                 | `bun run <s>`                   | `deno task <s>`   |
| Run binary    | `npx <p>`           | `yarn dlx <p>`              | `pnpm dlx <p>`             | `bunx <p>`                      | `dx <p>`          |
| Outdated      | `npm outdated`      | `yarn outdated`‡            | `pnpm outdated`            | `bun outdated`                  | `deno outdated`   |
| Audit         | `npm audit`         | `yarn npm audit`†           | `pnpm audit`               | `bun audit`                     | `deno audit`      |
| Why           | `npm ls <p>`        | `yarn why <p>`              | `pnpm why <p>`             | `bun why <p>`                   | `deno why <p>`    |
| Run a file    | `node f.js`         |                             |                            | `bun f.ts`                      | `deno f.ts`       |
| Run TS        | `ts-node f.ts`      |                             |                            | `bun f.ts`                      | `deno f.ts`       |
| Watch         | `nodemon f.js`      |                             |                            | `bun --watch f.ts`              | `deno watch f.ts` |
| Format        | prettier            |                             |                            | prettier                        | `deno fmt`        |
| Lint          | eslint              |                             |                            |                                 | `deno lint`       |
| Test          | jest, vitest        |                             |                            | `bun test`                      | `deno test`       |
| Coverage      | nyc, c8             |                             |                            |                                 | `deno coverage`   |
| Type-check    | `tsc --noEmit`      |                             |                            | `tsc`                           | `deno check`      |
| Bundle binary | pkg, nexe           |                             |                            | `bun build --compile`           | `deno compile`    |

† Yarn Berry (v2+) spelling. Yarn Classic (v1) uses
`yarn install --frozen-lockfile` and `yarn audit`.

‡ Yarn Classic only — Berry removed `yarn outdated`.

`dx` is a separate binary installed alongside Deno, and an alias for `deno x`.
It does not appear in the top-level `deno --help` output. Like `npx`, it runs
the package with the sandbox disabled.

## The four things that actually break

### `Requires net access to "..."` (or read, env, run)

Deno grants nothing by default. Add that specific permission, or `-A` while
still establishing the program works at all.

### `ReferenceError: require is not defined`

A file containing CommonJS is being parsed as ESM. `.cjs` is always CommonJS,
`.mjs` always ESM; `.js` and `.ts` follow `"type"` in the nearest
`package.json`. For a CommonJS project, set `"type": "commonjs"`.

### A dependency is broken, or `postinstall` never ran

Lifecycle scripts don't run by default. Native addons notice immediately.
Approvals are recorded in the config file, so this is one-time:

```bash
deno approve-scripts                              # interactive picker
deno install --allow-scripts=npm:better-sqlite3   # or name them directly
```

### A tool cannot find files inside `node_modules`

Deno's layout is pnpm-style: real files in `node_modules/.deno/`, exposed via
symlinks. Tools assuming npm's flat hoisted tree need:

```json
{ "nodeModulesLinker": "hoisted" }
```

## What has no Deno equivalent

Say so rather than improvising a workaround that won't hold:

- **Yarn Plug'n'Play.** Deno creates a real `node_modules`; `.pnp.cjs` is unused
  and `.yarnrc.yml` resolver settings don't transfer.
- **`yarn patch` / pnpm patched dependencies.** Vendor or fork.
- **`overrides` / `resolutions`.** Pin via an import map entry instead.
- **Registry and resolver tuning** in `.npmrc` / `.yarnrc.yml`.
- **Bun build features** — macros, HTMLRewriter, HTML entrypoints.

## Per-tool details

- `references/FROM_NPM.md` — lockfile seeding, `node_modules` layout, overrides
- `references/FROM_YARN.md` — Plug'n'Play, Berry vs Classic, workspaces
- `references/FROM_PNPM.md` — `pnpm-workspace.yaml`, `catalog:`, patches
- `references/FROM_BUN.md` — Bun API translation, `bunfig.toml`
- `references/NODE_APIS.md` — `node:` built-ins, `DENO_COMPAT`, CJS/ESM

## Further reading

- <https://docs.deno.com/runtime/migrate/> — official migration guides
- <https://docs.deno.com/runtime/fundamentals/node/> — Node and npm
  compatibility
- <https://docs.deno.com/runtime/reference/node_apis/> — per-module Node API
  status

<!-- chapter:end slug=migrate-to-deno -->
