Skip to main content
Understanding Deno’s architecture will help you navigate the codebase and contribute effectively.

High-Level Overview

Deno is built on three core technologies:

V8

Google’s JavaScript and WebAssembly engine

Rust

Systems programming language for the runtime

Tokio

Asynchronous runtime for Rust

Architecture Layers

Deno’s architecture is organized into several key layers:
┌─────────────────────────────────────┐
│         CLI (User Interface)         │  cli/
│   - Subcommands                      │
│   - Flag parsing                     │
│   - Package management               │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│       Runtime (Integration)          │  runtime/
│   - JavaScript runtime assembly      │
│   - Extension registration           │
│   - Worker initialization            │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│        Extensions (Native)           │  ext/
│   - fs, net, http, fetch, etc.       │
│   - System access for JavaScript     │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│         Core (Foundation)            │  libs/core/
│   - V8 integration                   │
│   - Op system                        │
│   - Module loader                    │
└─────────────────────────────────────┘

Key Directories

CLI Layer (cli/)

The user-facing interface and high-level integration.
Command-line flag parsingDefines the structure of all CLI commands and their flags. This is where you add new commands or modify existing command options.
CLI tools and subcommandsEach tool (fmt, lint, test, bundle, etc.) has its own module here. Simple tools are single files, complex tools have their own directories.Examples:
  • cli/tools/fmt.rs - Code formatter
  • cli/tools/test/ - Test runner (complex)
  • cli/tools/repl/ - Interactive REPL
Entry point and command routingmain.rs is minimal - it just calls deno::main() from lib.rs. The lib.rs file contains the main logic for routing commands to their handlers.
Module loading and resolutionHandles how Deno loads and resolves modules, including TypeScript compilation, remote modules, and import maps.
Language Server ProtocolPowers the Deno extension for editors like VS Code, providing features like autocomplete, diagnostics, and type checking.

Runtime Layer (runtime/)

Assembles the JavaScript runtime and integrates all extensions.
Worker initialization and managementCreates and manages JavaScript execution contexts. This is where extensions are registered and the V8 isolate is configured.Key concepts:
  • Main Worker - The primary JavaScript execution context
  • Web Workers - Background workers for parallel execution
  • Extension Registration - Wiring up native functionality
Permission systemImplements Deno’s security model with granular permissions for network, filesystem, environment variables, and more.

Extensions Layer (ext/)

Extensions provide native functionality to JavaScript.

ext/fs/

Filesystem operations (read, write, stat, etc.)

ext/net/

TCP and UDP networking

ext/http/

HTTP server and client APIs

ext/fetch/

Fetch API implementation

ext/webgpu/

WebGPU API for GPU access

ext/kv/

Key-value database

ext/node/

Node.js compatibility layer

ext/web/

Web standard APIs (streams, encoding, etc.)

Extension Structure

Each extension typically contains:
  • Rust code - Implements “ops” (operations) that JavaScript can call
  • JavaScript code - Provides high-level APIs that wrap the ops
  • Tests - Both unit and integration tests
Example extension structure:
ext/fs/
  lib.rs          # Rust ops for filesystem access
  *.js            # JavaScript APIs
  Cargo.toml      # Rust dependencies

Core Layer (libs/core/)

The foundation that powers everything.
Operations (Ops) are Rust functions that can be called from JavaScript.The op system provides:
  • Fast FFI between JavaScript and Rust
  • Async operation support
  • Resource management
  • Type safety
Example op definition:
#[op2]
#[string]
fn op_read_file_sync(#[string] path: String) -> Result<String, AnyError> {
  std::fs::read_to_string(path)
    .map_err(|e| e.into())
}
Manages the V8 JavaScript engine:
  • Isolate creation and configuration
  • Snapshot support for fast startup
  • Garbage collection integration
  • Inspector protocol support
Handles module loading and resolution:
  • ES modules
  • Dynamic imports
  • Import maps
  • Module caching

Test Infrastructure

tests/specs/

Spec Tests - Main integration tests that execute CLI commands and validate output

tests/unit/

Unit Tests - TypeScript/JavaScript unit tests

tests/testdata/

Test Data - Fixtures and test files used by the test suite

tests/wpt/

Web Platform Tests - Tests for web standards compliance

Key Concepts

Workers

Workers are JavaScript execution contexts in Deno.
The primary JavaScript execution context that runs your program.Created in runtime/worker.rs, it:
  • Loads and executes the main module
  • Has access to all granted permissions
  • Can spawn web workers

Resources

Resources are managed objects that are passed between Rust and JavaScript. Examples:
  • File handles
  • Network sockets
  • Database connections
  • Process handles
Resources are tracked by ID and automatically cleaned up when no longer referenced.

Permissions

Deno’s security model is based on explicit permissions:

--allow-read

Filesystem read access

--allow-write

Filesystem write access

--allow-net

Network access

--allow-env

Environment variable access

--allow-run

Subprocess execution

--allow-ffi

Foreign function interface
Permissions are checked at the runtime level in runtime/permissions.rs.

Module Resolution

Deno supports several module types and resolution strategies:

Module Types

1

ES Modules

Standard JavaScript modules with import/export
2

TypeScript

TypeScript files are type-checked and transpiled to JavaScript
3

Remote Modules

HTTP(S) URLs are fetched, cached, and executed
4

NPM Modules

Node.js packages via npm: specifiers
5

JSR Modules

JavaScript Registry packages via jsr: specifiers

Resolution Flow

Import Specifier

  Parse & Validate

  Check Cache

  Fetch (if remote)

  Type Check (if TS)

  Compile/Transform

  Execute

Extension System

Extensions are the bridge between JavaScript and native code.

How Extensions Work

1

Define Ops in Rust

Create functions using the #[op2] macro:
#[op2(fast)]
fn op_add(a: i32, b: i32) -> i32 {
  a + b
}
2

Create Extension

Bundle ops into an extension:
deno_core::extension!(
  my_extension,
  ops = [op_add],
);
3

Register in Runtime

Add the extension to the runtime in runtime/worker.rs
4

Call from JavaScript

The op is available in JavaScript:
const result = Deno.core.ops.op_add(1, 2);

Extension Lifecycle

  1. Initialization - Extension is registered with the runtime
  2. Snapshot - JavaScript code is included in the V8 snapshot for fast startup
  3. Runtime - Ops are callable from JavaScript
  4. Cleanup - Resources are freed when the runtime shuts down

Execution Flow

Here’s what happens when you run deno run script.ts:
1

Parse CLI flags

cli/args/flags.rs parses the command and flags
2

Initialize runtime

runtime/worker.rs creates a worker with all extensions
3

Load module

cli/module_loader.rs resolves and loads the script
4

Type check (if TypeScript)

cli/tsc/ performs type checking if needed
5

Execute

V8 executes the JavaScript code
6

Op calls

JavaScript calls ops (e.g., Deno.readFile())
7

Rust execution

Ops execute Rust code and return results
8

Event loop

Tokio event loop handles async operations
9

Cleanup

Resources are freed and the runtime shuts down

Communication Patterns

JavaScript ↔ Rust

// Calling a Rust op from JavaScript
const result = await Deno.core.ops.op_read_file("/path/to/file");

Sync vs Async Ops

  • Sync ops - Block until complete, used for fast operations
  • Async ops - Return a promise, use Tokio for async I/O
  • Fast ops - Optimized sync ops with minimal overhead

Performance Considerations

Snapshots

V8 snapshots enable fast startup by pre-compiling core JavaScript

Op Optimization

Fast ops minimize crossing the JS/Rust boundary

Async I/O

Tokio provides efficient async operations

Resource Pooling

Resources are pooled and reused where possible

Next Steps

Now that you understand the architecture:

Development Guide

Learn the development workflow and common tasks

Building from Source

Build Deno on your local machine

Start Contributing

Make your first contribution to Deno

Explore the Code

Browse the source code on GitHub

Build docs developers (and LLMs) love