# Deno Manual
[toc]
## Disclaimer
A word of caution: Deno is very much under development. We encourage brave early
adopters, but expect bugs large and small. The API is subject to change without
notice. [Bug reports](https://github.com/denoland/deno/issues) do help!
## Introduction
A secure JavaScript/TypeScript runtime built with V8, Rust, and Tokio
### Philosophy
Deno aims to be a productive and secure scripting environment for the modern
programmer.
It will always be distributed as a single executable - and that executable will
be sufficient software to run any deno program. Given a URL to a deno program,
you should be able to execute it with nothing more than the 50 megabyte deno
executable.
Deno explicitly takes on the role of both runtime and package manager. It uses a
standard browser-compatible protocol for loading modules: URLs.
Deno provides security guarantees about how programs can access your system with
the default being the most restrictive secure sandbox.
Deno provides a set of reviewed
(audited) standard modules that are guaranteed to work with Deno.
### Goals
- Support TypeScript out of the box.
- Like the browser, allows imports from URLs:
```ts
import * as log from "https://deno.land/std/log/mod.ts";
```
- Remote code is fetched and cached on first execution, and never updated until
the code is run with the `--reload` flag. (So, this will still work on an
airplane. See `~/.deno/src` for details on the cache.)
- Uses "ES Modules" and does not support `require()`.
- File system and network access can be controlled in order to run sandboxed
code. Access between V8 (unprivileged) and Rust (privileged) is only done via
serialized messages defined in this
[flatbuffer](https://github.com/denoland/deno/blob/master/cli/msg.fbs). This
makes it easy to audit. For example, to enable write access use the flag
`--allow-write` or for network access `--allow-net`.
- Only ship a single executable.
- Always dies on uncaught errors.
- Browser compatible: The subset of Deno programs which are written completely
in JavaScript and do not use the global `Deno` namespace (or feature test for
it), ought to also be able to be run in a modern web browser without change.
- [Aims to support top-level `await`.](https://github.com/denoland/deno/issues/471)
- Be able to serve HTTP efficiently.
([Currently it is relatively slow.](https://deno.land/benchmarks.html#req-per-sec))
- Provide useful tooling out of the box:
- command-line debugger
[not yet](https://github.com/denoland/deno/issues/1120)
- linter [not yet](https://github.com/denoland/deno/issues/1880)
- dependency inspector (`deno info`)
- code formatter (`deno fmt`),
### Non-goals
- No `package.json`.
- No npm.
- Not explicitly compatible with Node.
## Setup
### Binary Install
Deno works on OSX, Linux, and Windows. Deno is a single binary executable. It
has no external dependencies.
[deno_install](https://github.com/denoland/deno_install) provides convenience
scripts to download and install the binary.
Using Shell:
```shellsession
curl -fsSL https://deno.land/x/install/install.sh | sh
```
Using PowerShell:
```shellsession
iwr https://deno.land/x/install/install.ps1 | iex
```
Using [Scoop](https://scoop.sh/) (windows):
```shellsession
scoop install deno
```
Using [Homebrew](https://brew.sh/) (mac):
```shellsession
brew install deno
```
Deno can also be installed manually, by downloading a tarball or zip file at
[github.com/denoland/deno/releases](https://github.com/denoland/deno/releases).
These packages contain just a single executable file. You will have to set the
executable bit on Mac and Linux.
Once it's installed and in your `$PATH`, try it:
```shellsession
deno run https://deno.land/welcome.ts
```
### Build from source
Clone on Unix/MacOs
```bash
# Fetch deps.
git clone --recurse-submodules https://github.com/denoland/deno.git
```
Clone on Windows (with Admin privileges)
```bash
git clone -c core.symlinks=true --recurse-submodules https://github.com/denoland/deno.git
```
```bash
cd deno
./tools/setup.py
# You may need to ensure that sccache is running.
# (TODO it's unclear if this is necessary or not.)
# prebuilt/mac/sccache --start-server
# Build.
./tools/build.py
# Run.
./target/debug/deno run tests/002_hello.ts
# Test.
./tools/test.py
# Format code.
./tools/format.py
```
#### Prerequisites
To ensure reproducible builds, deno has most of its dependencies in a git
submodule. However, you need to install separately:
1. [Rust](https://www.rust-lang.org/en-US/install.html) >= 1.34.1
2. [Node](https://nodejs.org/)
3. Python 2.
[Not 3](https://github.com/denoland/deno/issues/464#issuecomment-411795578).
Extra steps for Mac users: install [XCode](https://developer.apple.com/xcode/)
:(
Extra steps for Windows users:
1. Add `python.exe` to `PATH` (e.g. `set PATH=%PATH%;C:\Python27\python.exe`)
2. Get [VS Community 2017](https://www.visualstudio.com/downloads/) with
"Desktop development with C++" toolkit and make sure to select the following
required tools listed below along with all C++ tools.
- Windows 10 SDK >= 10.0.17134
- Visual C++ ATL for x86 and x64
- Visual C++ MFC for x86 and x64
- C++ profiling tools
3. Enable "Debugging Tools for Windows". Go to "Control Panel" → "Programs" →
"Programs and Features" → Select "Windows Software Development Kit - Windows
10" → "Change" → "Change" → Check "Debugging Tools For Windows" → "Change" ->
"Finish".
4. Make sure you are using git version 2.19.2.windows.1 or newer.
#### Other useful commands
```bash
# Call ninja manually.
./third_party/depot_tools/ninja -C target/debug
# Build a release binary.
./tools/build.py --release deno
# List executable targets.
./third_party/depot_tools/gn ls target/debug //:* --as=output --type=executable
# List build configuration.
./third_party/depot_tools/gn args target/debug/ --list
# Edit build configuration.
./third_party/depot_tools/gn args target/debug/
# Describe a target.
./third_party/depot_tools/gn desc target/debug/ :deno
./third_party/depot_tools/gn help
# Update third_party modules
git submodule update
# Skip downloading binary build tools and point the build
# to the system provided ones (for packagers of deno ...).
./tools/setup.py --no-binary-download
export DENO_BUILD_ARGS="clang_base_path=/usr clang_use_chrome_plugins=false"
DENO_GN_PATH=/usr/bin/gn DENO_NINJA_PATH=/usr/bin/ninja ./tools/build.py
```
Environment variables: `DENO_BUILD_MODE`, `DENO_BUILD_PATH`, `DENO_BUILD_ARGS`,
`DENO_DIR`, `DENO_GN_PATH`, `DENO_NINJA_PATH`.
## API reference
### deno types
To get an exact reference of deno's runtime API, run the following in the
command line:
```shellsession
$ deno types
```
[This is what the output looks like.](https://gist.github.com/ry/46da4724168cdefa763e13207d27ede5)
### Reference websites
[TypeScript Deno API](https://deno.land/typedoc/index.html).
If you are embedding deno in a Rust program, see
[Rust Deno API](https://docs.rs/deno).
The Deno crate is hosted on [crates.io](https://crates.io/crates/deno).
## Examples
### An implementation of the unix "cat" program
In this program each command-line argument is assumed to be a filename, the file
is opened, and printed to stdout.
```ts
(async () => {
for (let i = 1; i < Deno.args.length; i++) {
let filename = Deno.args[i];
let file = await Deno.open(filename);
await Deno.copy(Deno.stdout, file);
file.close();
}
})();
```
The `copy()` function here actually makes no more than the necessary kernel ->
userspace -> kernel copies. That is, the same memory from which data is read
from the file, is written to stdout. This illustrates a general design goal for
I/O streams in Deno.
Try the program:
```shellsession
$ deno run --allow-read https://deno.land/std/examples/cat.ts /etc/passwd
```
### TCP echo server
This is an example of a simple server which accepts connections on port 8080,
and returns to the client anything it sends.
```ts
const { listen, copy } = Deno;
(async () => {
const addr = "0.0.0.0:8080";
const listener = listen("tcp", addr);
console.log("listening on", addr);
while (true) {
const conn = await listener.accept();
copy(conn, conn);
}
})();
```
When this program is started, the user is prompted for permission to listen on
the network:
```shellsession
$ deno run https://deno.land/std/examples/echo_server.ts
⚠️ Deno requests network access to "listen". Grant? [a/y/n/d (a = allow always, y = allow once, n = deny once, d = deny always)]
```
For security reasons, deno does not allow programs to access the network without
explicit permission. To avoid the console prompt, use a command-line flag:
```shellsession
$ deno run --allow-net https://deno.land/std/examples/echo_server.ts
```
To test it, try sending a HTTP request to it by using curl. The request gets
written directly back to the client.
```shellsession
$ curl http://localhost:8080/
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/7.54.0
Accept: */*
```
It's worth noting that like the `cat.ts` example, the `copy()` function here
also does not make unnecessary memory copies. It receives a packet from the
kernel and sends back, without further complexity.
### Inspecting and revoking permissions
Sometimes a program may want to revoke previously granted permissions. When a
program, at a later stage, needs those permissions, a new prompt will be
presented to the user.
```ts
const { permissions, revokePermission, open, remove } = Deno;
(async () => {
// lookup a permission
if (!permissions().write) {
throw new Error("need write permission");
}
const log = await open("request.log", "a+");
// revoke some permissions
revokePermission("read");
revokePermission("write");
// use the log file
const encoder = new TextEncoder();
await log.write(encoder.encode("hello\n"));
// this will prompt for the write permission or fail.
await remove("request.log");
})();
```
### File server
This one serves a local directory in HTTP.
```bash
alias file_server="deno run --allow-net --allow-read \
https://deno.land/std/http/file_server.ts"
```
Run it:
```shellsession
$ file_server .
Downloading https://deno.land/std/http/file_server.ts...
[...]
HTTP server listening on http://0.0.0.0:4500/
```
And if you ever want to upgrade to the latest published version:
```shellsession
$ file_server --reload
```
### Permissions whitelist
deno also provides permissions whitelist.
This is an example to restrict File system access by whitelist.
```shellsession
$ deno run --allow-read=/usr https://deno.land/std/examples/cat.ts /etc/passwd
⚠️ Deno requests read access to "/etc/passwd". Grant? [a/y/n/d (a = allow always, y = allow once, n = deny once, d = deny always)]
```
You can grant read permission under `/etc` dir
```shellsession
$ deno run --allow-read=/etc https://deno.land/std/examples/cat.ts /etc/passwd
```
`--allow-write` works same as `--allow-read`.
This is an example to restrict host.
```ts
(async () => {
const result = await fetch("https://deno.land/std/examples/echo_server.ts");
})();
```
```shellsession
$ deno run --allow-net=deno.land allow-net-whitelist-example.ts
```
### Run subprocess
[API Reference](https://deno.land/typedoc/index.html#run)
Example:
```ts
async function main() {
// create subprocess
const p = Deno.run({
args: ["echo", "hello"]
});
// await its completion
await p.status();
}
main();
```
Run it:
```shellsession
$ deno run --allow-run ./subprocess_simple.ts
hello
```
By default when you use `Deno.run()` subprocess inherits `stdin`, `stdout` and
`stderr` of parent process. If you want to communicate with started subprocess
you can use `"piped"` option.
```ts
async function main() {
const decoder = new TextDecoder();
const fileNames = Deno.args.slice(1);
const p = Deno.run({
args: [
"deno",
"run",
"--allow-read",
"https://deno.land/std/examples/cat.ts",
...fileNames
],
stdout: "piped",
stderr: "piped"
});
const { code } = await p.status();
if (code === 0) {
const rawOutput = await p.output();
await Deno.stdout.write(rawOutput);
} else {
const rawError = await p.stderrOutput();
const errorString = decoder.decode(rawError);
console.log(errorString);
}
Deno.exit(code);
}
main();
```
When you run it:
```shellsession
$ deno run --allow-run ./subprocess.ts
[file content]
$ deno run --allow-run ./subprocess.ts non_existent_file.md
Uncaught NotFound: No such file or directory (os error 2)
at DenoError (deno/js/errors.ts:22:5)
at maybeError (deno/js/errors.ts:41:12)
at handleAsyncMsgFromRust (deno/js/dispatch.ts:27:17)
```
### Linking to third party code
In the above examples, we saw that Deno could execute scripts from URLs. Like
browser JavaScript, Deno can import libraries directly from URLs. This example
uses a URL to import a test runner library:
```ts
import { test, runIfMain } from "https://deno.land/std/testing/mod.ts";
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
test(function t1() {
assertEquals("hello", "hello");
});
test(function t2() {
assertEquals("world", "world");
});
runIfMain(import.meta);
```
Try running this:
```shellsession
$ deno run test.ts
running 2 tests
test t1 ... ok
test t2 ... ok
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```
Note that we did not have to provide the `--allow-net` flag for this program,
and yet it accessed the network. The runtime has special access to download
imports and cache them to disk.
Deno caches remote imports in a special directory specified by the `$DENO_DIR`
environmental variable. It defaults to the system's cache directory if
`$DENO_DIR` is not specified. The next time you run the program, no downloads
will be made. If the program hasn't changed, it won't be recompiled either. The
default directory is:
- On Linux/Redox: `$XDG_CACHE_HOME/deno` or `$HOME/.cache/deno`
- On Windows: `%LOCALAPPDATA%/deno` (`%LOCALAPPDATA%` = `FOLDERID_LocalAppData`)
- On macOS: `$HOME/Library/Caches/deno`
- If something fails, it falls back to `$HOME/.deno`
**But what if `https://deno.land/` goes down?** Relying on external servers is
convenient for development but brittle in production. Production software should
always bundle its dependencies. In Deno this is done by checking the `$DENO_DIR`
into your source control system, and specifying that path as the `$DENO_DIR`
environmental variable at runtime.
**How do you import to a specific version?** Simply specify the version in the
URL. For example, this URL fully specifies the code being run:
`https://unpkg.com/liltest@0.0.5/dist/liltest.js`. Combined with the
aforementioned technique of setting `$DENO_DIR` in production to stored code,
one can fully specify the exact code being run, and execute the code without
network access.
**It seems unwieldy to import URLs everywhere. What if one of the URLs links to
a subtly different version of a library? Isn't it error prone to maintain URLs
everywhere in a large project?** The solution is to import and re-export your
external libraries in a central `deps.ts` file (which serves the same purpose as
Node's `package.json` file). For example, let's say you were using the above
testing library across a large project. Rather than importing
`"https://deno.land/std/testing/mod.ts"` everywhere, you could create a
`deps.ts` file the exports the third-party code:
```ts
export { test, assertEquals } from "https://deno.land/std/testing/mod.ts";
```
And throughout project one can import from the `deps.ts` and avoid having many
references to the same URL:
```ts
import { test, assertEquals } from "./deps.ts";
```
This design circumvents a plethora of complexity spawned by package management
software, centralized code repositories, and superfluous file formats.
### Testing if current file is the main program
To test if the current script has been executed as the main input to the program
check `import.meta.main`.
```ts
if (import.meta.main) {
console.log("main");
}
```
## Command line interface
### Flags
```shellsession
deno
A secure runtime for JavaScript and TypeScript built with V8, Rust, and Tokio.
Docs: https://deno.land/manual.html
Modules: https://github.com/denoland/deno_std
Bugs: https://github.com/denoland/deno/issues
To run the REPL:
deno
To execute a sandboxed script:
deno https://deno.land/welcome.ts
To evaluate code from the command line:
deno eval "console.log(30933 + 404)"
To get help on the another subcommands (run in this case):
deno help run
USAGE:
deno [FLAGS] [OPTIONS] [SUBCOMMAND]
FLAGS:
-A, --allow-all Allow all permissions
--allow-env Allow environment access
--allow-hrtime Allow high resolution time measurement
--allow-run Allow running subprocesses
-h, --help Prints help information
-D, --log-debug Log debug output
--no-prompt Do not use prompts
-r, --reload Reload source code cache (recompile TypeScript)
--v8-options Print V8 command line options
OPTIONS:
--allow-net= Allow network access
--allow-read= Allow file system read access
--allow-write= Allow file system write access
-c, --config Load compiler configuration file
--importmap Load import map file
--v8-flags= Set V8 command line options
SUBCOMMANDS: