Skip to main content

Deno Runtime Quick Start

Deno (/ˈdiːnoʊ/, pronounced dee-no) is a JavaScript, TypeScript, and WebAssembly runtime with secure defaults and a great developer experience. It's built on V8, Rust, and Tokio.

Deno is free and open source software under the MIT license.

Let's create and run your first Deno program in under five minutes, and introduce you to a few key features of the runtime.

Install Deno

Install the Deno runtime on your system using one of the terminal commands below.

curl -fsSL https://deno.land/x/install/install.sh | sh

Additional installation options can be found here. After installation, you should have the deno executable available on your system path. You can confirm this is the case by running this command in your terminal:

deno --version

Create and run a TypeScript program

While you are welcome to use pure JavaScript, Deno has built-in support for TypeScript as well. In your terminal, create a new file called hello.ts, and include the following code.

hello.ts
interface Person {
firstName: string,
lastName: string
}

function sayHello(p: Person): string {
return `Hello, ${p.firstName}!`;
}

const ada: Person = {
firstName: "Ada",
lastName: "Lovelace"
};

console.log(sayHello(ada));

This program declares an interface for a Person, and defines a function that prints a message to the console using this data type. You can execute the code in this example using the deno run command.

deno run -A hello.ts

You can learn more about using TypeScript in Deno here.

Built-in web APIs and the Deno namespace

Deno aims to provide a browser-like programming environment, implementing web standard APIs that exist in front-end JavaScript. For example, the fetch API is available in the global scope, just as in the browser. To see this in action, replace the contents of hello.ts with the following code.

const site = await fetch("https://www.deno.com");
console.log(await site.text());

And then run it with:

deno run -A hello.ts

For APIs that don't exist as a web standard (like accessing variables from the system environment, or manipulating the file system), those APIs are exposed in the Deno namespace. Replace the contents of hello.ts with the following code, which will start an HTTP server on localhost:8000.

Deno.serve((_request: Request) => {
return new Response("Hello, world!");
});

Run the script above with:

deno run -A hello.ts

Learn more about the web-standard APIs built in to Deno and the Deno namespace APIs.

Runtime security

A major feature of Deno is runtime security by default, meaning that you as the developer must explicitly allow your code to access potentially sensitive APIs like file system access, network connectivity, and access to environment variables.

So far, we've been running all of our scripts with the -A flag, which grants all runtime feature access to our scripts. This is the most permissive mode to run a Deno program, but usually you'll want to grant your code only the permissions it needs to run.

To see this in action, let's replace the contents of hello.ts again with the fetch example from earlier.

const site = await fetch("https://www.deno.com");
console.log(await site.text());

Run this program without the -A flag - what happens then?

deno run hello.ts

Without any permission flags passed in, you'll see security prompts that look something like this:

kevin@kevin-deno scratchpad % deno run index.ts
✅ Granted net access to "www.deno.com".
┌ ⚠️ Deno requests net access to "deno.com".
├ Requested by `fetch()` API.
├ Run again with --allow-net to bypass this prompt.
└ Allow? [y/n/A] (y = yes, allow; n = no, deny; A = allow all net permissions) >

In the prompt, you might have noticed that it mentions the CLI flag you'd need to run your code with permission to access the network - the --allow-net flag. If you run the script again using this flag, you won't be prompted to interactively grant network access to your script:

deno run --allow-net hello.ts

For simplicity, we will sometimes show examples that use deno run -A ..., but whenever possible (and in your production or CI environments), we'd encourage you to take advantage of Deno's full suite of configurable runtime security options.

Importing JavaScript modules

Most of the time, you will want to break up your program into multiple files. Again favoring web standards and a browser-like programming model, Deno supports this through ECMAScript modules. Consider the earlier TypeScript example we showed you:

hello.ts
interface Person {
firstName: string,
lastName: string
}

function sayHello(p: Person): string {
return `Hello, ${p.firstName}!`;
}

const ada: Person = {
firstName: "Ada",
lastName: "Lovelace"
};

console.log(sayHello(ada));

You might want to break this program up such that the Person interface and the sayHello function are in a separate module. To do this, create a new file in the same directory called person.ts and include the following code:

person.ts
export default interface Person {
firstName: string,
lastName: string
}

export function sayHello(p: Person): string {
return `Hello, ${p.firstName}!`;
}

This module creates a named export for the sayHello function, and a default export for the Person interface.

Back in hello.ts, you would consume this module using the import keyword.

hello.ts
import Person, { sayHello } from "./person.ts";

const ada: Person = {
lastName: "Lovelace",
firstName: "Ada",
};

console.log(sayHello(ada));
File extensions required in imports

Note that file extensions are required when importing modules - import logic in Deno works as it does in the browser, where you would include the full file name of your imports.

You can learn more about the module system in Deno here.

Remote modules and the Deno standard library

Deno supports loading and executing code from URLs, much as you would using a <script> tag in the browser. In Deno 1.x, the standard library and most third-party modules are distributed on HTTPS URLs.

To see this in action, let's create a test for the person.ts module we created above. Deno provides a built-in test runner, which uses an assertion module distributed via HTTPS URL.

person_test.ts
import { assertEquals } from "https://deno.land/std@0.202.0/assert/mod.ts";
import Person, { sayHello } from "./person.ts";

Deno.test("sayHello function", () => {
const grace: Person = {
lastName: "Hopper",
firstName: "Grace",
};

assertEquals("Hello, Grace!", sayHello(grace));
});

Run this test with:

deno test person_test.ts

The output should look something like this:

kevin@kevin-deno scratchpad % deno test person_test.ts
Check file:///Users/kevin/dev/denoland/scratchpad/person_test.ts
running 1 test from ./person_test.ts
sayHello function ... ok (4ms)

ok | 1 passed | 0 failed (66ms)

There's much more to explore with the standard library and third-party modules - be sure to check them out!

Configure your project with deno.json

Deno projects don't require a configuration file by default, but sometimes it's convenient to store settings, admin scripts, and dependency configuration in a well-known location. In Deno, that file is deno.json or deno.jsonc. This file acts a bit like a package.json file in Node.js.

One of the things you can use deno.json for is configuring an import map, which will let you set up aliases for frequently used modules.

To demonstrate, let's pin the version of the standard library we want to use in our project to version 0.202.0.

Create a deno.jsonc file with the following contents.

deno.jsonc
{
"imports": {
// The dollar sign in front of "std" isn't special - it's an optional
// convention to show that $std is an alias set up in an import map
"$std/": "https://deno.land/std@0.202.0/"
}
}

Now, open up your test file from before, and change it to use this import alias.

person_test.ts
import { assertEquals } from "$std/assert/mod.ts";
import Person, { sayHello } from "./person.ts";

Deno.test("sayHello function", () => {
const grace: Person = {
lastName: "Hopper",
firstName: "Grace",
};

assertEquals("Hello, Grace!", sayHello(grace));
});

Running the test with deno test person_test.ts should work just as before, but you might notice that Deno downloads a few extra files and generates a deno.lock file, specifying a set of files depended on by your code. Both deno.jsonc and deno.lock can be checked in to source control.

Learn more about configuring your project here.

Node.js APIs and npm packages

Deno provides a compatibility layer that enables your code to use Node.js built-in modules and third-party modules from npm. Using Node and npm modules in your code looks a lot like using standard Deno modules, except you'll use either a node: or npm: specifier when importing Node built-ins or npm moudles, respectively.

To see how it works, create a file called server.js and include the following - a simple HTTP server using the popular Express framework.

import express from "npm:express@4";

const app = express();

app.get("/", (request, response) => {
response.send("Hello from Express!");
});

app.listen(3000);

With node: and npm: specifiers, you can bring the best of the Node.js ecosystem with you to Deno. Learn more about Node and npm support.

Configure your IDE

Deno development is supported in a number of major IDEs. A popular option is Visual Studio Code, with an official extension maintained by the Deno team. Install the extension and enable it in your VS Code workspace by choosing the Deno: Initialize Workspace Configuration option in the command palette.

command palette setup

Not a VS Code user? Find an integration for your favorite editor here.

Web application frameworks

A common use case for Deno is building data-driven web applications. Doing that usually requires use of a higher-level web framework, for which many options exist in the Deno ecosystem. Here are a few of the most popular choices.

Deno-native frameworks

  • Deno Fresh - Fresh is a web framework designed for Deno. Pages are server-rendered by default, with the option to include interactive islands that run JavaScript on the client. If you're new to Deno and looking for a place to start, we recommend trying Fresh first!
  • Hono - Hono is a light-weight web framework in the tradition of Express. Great for API servers and simple web applications.

Deno-compatible frameworks

  • Astro - Astro is a modern web framework that was originally designed for Node.js, but runs great on Deno as well. We recommend starting with this template.
  • SvelteKit - SvelteKit is another more runtime-agnostic web framework that can be used with Deno. We recommend starting with this template.
  • Nuxt (Vue) - Nuxt is a hybrid SSR and client-side framework that works with Deno. We recommend starting with this template.

Many more frameworks support Deno than are listed here, but we'd recommend these as a great starting point.

Deploying to production

When you're ready to move into production, your easiest option will be Deno Deploy. Deno Deploy makes it easy to create fast, globally distributed serverless applications with Deno.

You can also host Deno in almost any cloud environment.

Next Steps

We've only just scratched the surface of what's possible with Deno. Here are a few resources you might want to check out next.