denoland/deno
A modern runtime for JavaScript and TypeScript.
Executes JavaScript and TypeScript with secure defaults and native performance
Source code enters through CLI argument parsing which resolves module specifiers and loads configuration. The module loader fetches source code (local files or remote URLs), TypeScript gets transpiled through SWC/TSC, modules are loaded into V8 isolate, and JavaScript execution proceeds with op calls bridging back to Rust implementations for I/O and system operations. Results flow back through the op system to JavaScript and finally to stdout/files.
Under the hood, the system uses 3 feedback loops, 4 data pools, 4 control points to manage its runtime behavior.
A 8-component repository. 4956 files analyzed. Data flows through 6 distinct pipeline stages.
How Data Flows Through the System
Source code enters through CLI argument parsing which resolves module specifiers and loads configuration. The module loader fetches source code (local files or remote URLs), TypeScript gets transpiled through SWC/TSC, modules are loaded into V8 isolate, and JavaScript execution proceeds with op calls bridging back to Rust implementations for I/O and system operations. Results flow back through the op system to JavaScript and finally to stdout/files.
- Parse CLI arguments and load configuration — CliArgs::from_flags processes command line arguments, loads deno.json/deno.jsonc configuration files, resolves import maps, and constructs PermissionsContainer with allow/deny rules
- Resolve module specifiers — ModuleLoader takes import strings and resolves them to ModuleSpecifier URLs using import maps, package.json resolution for Node compatibility, and JSR/NPM package resolution [Import strings → ModuleSpecifier]
- Fetch and cache module source — Source is fetched from file system or HTTP, cached in GlobalHttpCache, and TypeScript files are transpiled to JavaScript using SWC with configured compiler options [ModuleSpecifier → Module source code]
- Initialize V8 isolate with extensions — JsRuntime creates V8 isolate, loads startup snapshot, registers ops from all extensions (fetch, crypto, fs, etc.), and initializes OpState with permissions and resources [Runtime configuration → JsRuntime]
- Load and execute JavaScript modules — ModuleLoader provides source to V8, modules are compiled and linked, main module is evaluated, and event loop processes microtasks and op completions [Module source code → Module execution results]
- Process op calls between JavaScript and Rust — OpDispatcher handles calls from JavaScript to Rust functions, serializes arguments using serde_v8, executes Rust implementation with permission checks, and returns results to JavaScript [Op calls from JavaScript → Op results to JavaScript]
Data Models
The data structures that flow between stages — the contracts that hold the system together.
libs/core/lib.rsRefCell-wrapped state container holding per-isolate data including resource registry, permissions, extension state, and op-specific data structures
Created during isolate initialization, mutated during op calls, and cleaned up when isolate shuts down
deno_ast crateURL-like identifier for modules with scheme (file://, https://, npm:, jsr:) and normalized path/query components
Parsed from import strings, resolved through module graph, and used to fetch/load module source code
libs/core/lib.rsTrait object with ResourceId, name, and cleanup behavior - concrete types include files, network connections, timers, and crypto operations
Allocated with unique ResourceId, stored in OpState registry, accessed during ops, and cleaned up on close or isolate shutdown
libs/core/lib.rsV8 isolate wrapper containing OpState, module loader, snapshot data, extensions list, and event loop integration
Created with configuration and snapshot, loads modules, executes JavaScript, processes ops, and manages isolate lifecycle
runtime/permissions/lib.rsStructured permissions with allow/deny lists for network, file system, environment, subprocess, and other capabilities
Initialized from CLI flags and config, queried before resource operations, and can be dynamically modified through permission APIs
Hidden Assumptions
Things this code relies on but never validates. These are the things that cause silent failures when the system changes.
The JSR_URL lazy static can be safely constructed at runtime using CliSys::default() and will remain valid for the entire program lifetime
If this fails: If the JSR URL resolution fails during first access, the entire program crashes with a panic since Lazy::new() doesn't handle initialization errors gracefully
cli/args/mod.rs:jsr_url
The snapshot file exists at the path computed by concat!(env!("OUT_DIR"), "/RUNJS_SNAPSHOT.bin") and is valid V8 heap data
If this fails: If build.rs doesn't generate the snapshot or generates corrupt data, include_bytes! will either fail at compile time or the runtime will crash when trying to deserialize invalid V8 heap state
libs/core/examples/snapshot/src/main.rs:RUNTIME_SNAPSHOT
The sequence of js_runtime.load_main_es_module(), js_runtime.mod_evaluate(), and js_runtime.run_event_loop() must be called in this exact order without interleaving other operations
If this fails: If the order is changed or operations are interleaved, the module evaluation might not complete properly or the event loop might process tasks before the module is fully loaded, leading to runtime errors or undefined behavior
libs/core/examples/snapshot/src/main.rs:run_js
The denort::main() function exists and is accessible, presumably from a binary crate dependency
If this fails: If the denort crate is not properly linked or the main function doesn't exist, this will fail at compile time, but there's no fallback or error handling mechanism
cli/rt/main.rs:main
The current working directory exists and is accessible when current_dir() is called
If this fails: If the process doesn't have permission to read the current directory or it was deleted after the process started, current_dir() returns an error that gets propagated up, but the error message may be confusing to users expecting a JavaScript file issue
libs/core/examples/snapshot/src/main.rs:current_dir
The snapshot binary data included at compile time fits within memory limits and doesn't exceed maximum static data size constraints
If this fails: For very large snapshots, this could cause compilation to fail or result in excessive binary size and memory usage at startup, but there's no size validation or chunking mechanism
ext/fetch/lib.rs:RUNTIME_SNAPSHOT
The JSR URL configuration and CliSys default values remain stable between the time the lazy static is initialized and when it's accessed throughout program execution
If this fails: If JSR configuration changes dynamically or CliSys behavior varies based on runtime conditions, the cached URL might become stale or incorrect, leading to failed module resolution
cli/args/mod.rs:JSR_URL lazy static
The FsModuleLoader is compatible with the RUNTIME_SNAPSHOT and extensions provided, and their initialization order doesn't matter
If this fails: If the snapshot contains state that conflicts with FsModuleLoader expectations or extension initialization, the runtime might initialize successfully but fail unpredictably during module loading
libs/core/examples/snapshot/src/main.rs:RuntimeOptions
The file_path parameter refers to a file that exists and is readable when deno_core::resolve_path is called
If this fails: If the file doesn't exist, resolve_path succeeds but load_main_es_module will fail later with a potentially confusing error about module loading rather than file existence
libs/core/examples/snapshot/src/main.rs:resolve_path
The tokio runtime can be created with enable_all() and current_thread configuration without conflicting with any existing async runtime or thread pool setup
If this fails: If there's already a tokio runtime active or incompatible async setup, Builder::build() might fail or create a nested runtime that causes deadlocks in async operations
libs/core/examples/snapshot/src/main.rs:tokio runtime
System Behavior
How the system operates at runtime — where data accumulates, what loops, what waits, and what controls what.
Data Pools
HTTP responses cached to disk by URL with headers and metadata for offline access and performance
Maps ResourceId to Resource instances for files, network connections, timers, and other system objects
Tracks loaded modules by ModuleSpecifier with compilation state and dependency information
Stores TypeScript type checking results to avoid recomputation when source hasn't changed
Feedback Loops
- Module dependency resolution (recursive, balancing) — Trigger: Import statement in module. Action: Resolves import specifier, loads referenced module, processes its imports recursively. Exit: All dependencies loaded or circular dependency detected.
- Op async completion (polling, balancing) — Trigger: Async op initiated from JavaScript. Action: Event loop polls for op completion, processes result, resumes JavaScript execution. Exit: Op completes successfully or fails.
- Permission escalation (self-correction, balancing) — Trigger: Permission denied error. Action: Runtime can prompt user or fail operation based on configuration. Exit: Permission granted, denied, or process exits.
Delays
- Network module fetching (async-processing, ~variable (network latency)) — Module loading waits for HTTP responses before compilation can proceed
- TypeScript compilation (compilation, ~proportional to code size) — Initial module load includes transpilation overhead
- V8 snapshot deserialization (warmup, ~~10-50ms) — Runtime startup loads serialized heap state to skip JavaScript bootstrap
Control Points
- Permission flags (runtime-toggle) — Controls: Which system resources JavaScript can access (--allow-net, --allow-read, etc.)
- Unstable features (feature-flag) — Controls: Enable experimental APIs like WebGPU, KV, Cron through --unstable-* flags
- Import map configuration (architecture-switch) — Controls: Module resolution strategy - bare specifiers map to URLs or file paths. Default: import_map.json
- Node compatibility mode (runtime-toggle) — Controls: Enable Node.js API compatibility and CommonJS module loading
Technology Stack
JavaScript engine for executing user code with JIT compilation and garbage collection
Async runtime providing event loop, futures, and async I/O primitives for non-blocking operations
TypeScript to JavaScript transpiler integrated for fast compilation of .ts files
HTTP client/server implementation used by fetch extension for network requests
TLS implementation providing secure connections for HTTPS and WebSocket operations
Embedded database for caching compiled modules, type check results, and KV storage
Serialization bridge between Rust data structures and V8 JavaScript values
Key Components
- JsRuntime (orchestrator) — Manages V8 JavaScript isolate lifecycle, module loading, op dispatch, and event loop integration - the central coordinator between Rust and JavaScript execution
libs/core/lib.rs - ModuleLoader (loader) — Resolves module specifiers to source code, handles different module types (ES modules, CommonJS, JSON), and manages module caching and dependency resolution
libs/core/lib.rs - OpDispatcher (dispatcher) — Routes JavaScript function calls to Rust implementations through the op system, handles serialization/deserialization, and manages async op completion
libs/core/lib.rs - PermissionsContainer (validator) — Enforces security boundaries by checking resource access against configured allow/deny lists before permitting file, network, or subprocess operations
runtime/permissions/lib.rs - ExtensionBuilder (factory) — Constructs runtime extensions by registering ops, providing JavaScript modules, and setting up extension-specific state in the isolate
libs/core/lib.rs - CliArgs (processor) — Parses command line arguments and configuration files to produce structured configuration that drives all runtime behavior including permissions, module resolution, and execution mode
cli/args/mod.rs - HttpClientProvider (factory) — Creates configured HTTP clients with TLS settings, proxy support, and certificate validation for fetch operations and module downloads
ext/fetch/lib.rs - FsFetchHandler (adapter) — Bridges file system operations to HTTP fetch interface, allowing file:// URLs to be handled through the same fetch pipeline as HTTP requests
ext/fetch/fs_fetch_handler.rs
Package Structure
Main Deno CLI binary that orchestrates all runtime operations including argument parsing, module resolution, and execution coordination.
Shared library components used by CLI including NPM handling, worker management, and system abstractions.
Standalone runtime binary for executing compiled Deno applications without the full CLI toolchain.
Core runtime components including permissions system, process management, and JavaScript execution environment.
Fundamental V8 integration layer providing JavaScript engine bindings, module loading, and op system for Rust-JS communication.
Procedural macro system for generating JavaScript-Rust FFI bindings and runtime operation definitions.
Explore the interactive analysis
See the full architecture map, data flow, and code patterns visualization.
Analyze on CodeSeaRelated Repository Repositories
Frequently Asked Questions
What is deno used for?
Executes JavaScript and TypeScript with secure defaults and native performance denoland/deno is a 8-component repository written in Rust. Data flows through 6 distinct pipeline stages. The codebase contains 4956 files.
How is deno architected?
deno is organized into 4 architecture layers: CLI Layer, Runtime Layer, Extension Layer, Core Layer. Data flows through 6 distinct pipeline stages. This layered structure keeps concerns separated and modules independent.
How does data flow through deno?
Data moves through 6 stages: Parse CLI arguments and load configuration → Resolve module specifiers → Fetch and cache module source → Initialize V8 isolate with extensions → Load and execute JavaScript modules → .... Source code enters through CLI argument parsing which resolves module specifiers and loads configuration. The module loader fetches source code (local files or remote URLs), TypeScript gets transpiled through SWC/TSC, modules are loaded into V8 isolate, and JavaScript execution proceeds with op calls bridging back to Rust implementations for I/O and system operations. Results flow back through the op system to JavaScript and finally to stdout/files. This pipeline design reflects a complex multi-stage processing system.
What technologies does deno use?
The core stack includes V8 (JavaScript engine for executing user code with JIT compilation and garbage collection), Tokio (Async runtime providing event loop, futures, and async I/O primitives for non-blocking operations), SWC (TypeScript to JavaScript transpiler integrated for fast compilation of .ts files), Hyper (HTTP client/server implementation used by fetch extension for network requests), Rustls (TLS implementation providing secure connections for HTTPS and WebSocket operations), SQLite (Embedded database for caching compiled modules, type check results, and KV storage), and 1 more. A focused set of dependencies that keeps the build manageable.
What system dynamics does deno have?
deno exhibits 4 data pools (GlobalHttpCache, ResourceRegistry), 3 feedback loops, 4 control points, 3 delays. The feedback loops handle recursive and polling. These runtime behaviors shape how the system responds to load, failures, and configuration changes.
What design patterns does deno use?
4 design patterns detected: Extension Pattern, Op System FFI, Resource Management, Snapshot Optimization.
Analyzed on April 20, 2026 by CodeSea. Written by Karolina Sarna.