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.
- macOS
- Windows
- Linux
curl -fsSL https://deno.land/x/install/install.sh | sh
irm https://deno.land/install.ps1 | iex
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.
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:
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:
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.
import Person, { sayHello } from "./person.ts";
const ada: Person = {
lastName: "Lovelace",
firstName: "Ada",
};
console.log(sayHello(ada));
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.
import { assertEquals } from "https://deno.land/std@0.206.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.206.0
.
Create a deno.jsonc
file with the following contents.
{
"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.206.0/"
}
}
Now, open up your test file from before, and change it to use this import alias.
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 modules, 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.
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.
- Install & Setup - options for installing and configuring Deno
- Tutorials and Examples - Sample code and use cases for Deno
- Deno by Example - Code snippets to learn Deno by example