Skip to main content
Ganesh Joshi
Back to Blogs

Deno for web development: a modern JavaScript runtime

February 19, 20264 min read
Tips
Terminal with JavaScript runtime on screen

Deno is a JavaScript and TypeScript runtime from Ryan Dahl, the creator of Node.js. It addresses some design decisions in Node that Dahl later regretted. Deno runs TypeScript natively, has built-in tools, and defaults to a secure execution model.

What Deno provides

Feature Description
Native TypeScript No build step needed for TS
Built-in tooling Formatter, linter, test runner, bundler
Secure by default No file/network access without permission
URL imports Import from URLs, no node_modules by default
npm compatibility Run npm packages with npm: specifier
Web standard APIs Fetch, Web Crypto, streams work natively

Installation

# macOS/Linux
curl -fsSL https://deno.land/install.sh | sh

# Windows (PowerShell)
irm https://deno.land/install.ps1 | iex

# Or via package managers
brew install deno

Verify installation:

deno --version

Running TypeScript

No configuration needed:

// hello.ts
const message: string = "Hello from Deno!";
console.log(message);
deno run hello.ts

TypeScript just works. No tsconfig, no build step for simple scripts.

Permissions

Deno requires explicit permissions:

# No permissions (fails if code tries to access network)
deno run app.ts

# Allow network access
deno run --allow-net app.ts

# Allow specific hosts
deno run --allow-net=api.example.com app.ts

# Allow file read
deno run --allow-read app.ts

# Allow specific directory
deno run --allow-read=./data app.ts

# Allow environment variables
deno run --allow-env app.ts

# Allow all (like Node.js)
deno run -A app.ts
Permission Flag
Network --allow-net
File read --allow-read
File write --allow-write
Environment --allow-env
Run subprocesses --allow-run
FFI --allow-ffi
All -A or --allow-all

Imports and dependencies

URL imports

import { serve } from "https://deno.land/std@0.220.0/http/server.ts";
import { z } from "https://deno.land/x/zod@v3.22.0/mod.ts";

npm packages

import express from "npm:express@4";
import { z } from "npm:zod";

Import maps

Create deno.json:

{
  "imports": {
    "@std/": "https://deno.land/std@0.220.0/",
    "zod": "npm:zod@3"
  }
}

Then import cleanly:

import { serve } from "@std/http/server.ts";
import { z } from "zod";

Built-in tooling

Formatter

deno fmt              # Format all files
deno fmt src/         # Format directory
deno fmt --check      # Check without writing

Linter

deno lint             # Lint all files
deno lint src/        # Lint directory

Test runner

// math_test.ts
import { assertEquals } from "https://deno.land/std@0.220.0/assert/mod.ts";

Deno.test("addition", () => {
  assertEquals(1 + 1, 2);
});
deno test

Task runner

In deno.json:

{
  "tasks": {
    "dev": "deno run --watch --allow-net main.ts",
    "test": "deno test --allow-read",
    "lint": "deno lint && deno fmt --check"
  }
}
deno task dev

Deno vs Node.js

Aspect Deno Node.js
TypeScript Native Requires build step
Tooling Built-in Separate packages
Security Permissions required Full access by default
Imports URLs or npm: node_modules
Ecosystem Growing + npm compat Massive
Deployment Deno Deploy, Docker Everywhere

When to choose Deno

  • New projects wanting minimal setup
  • Scripts and CLIs
  • Projects prioritizing security
  • Teams wanting built-in tooling

When to stay with Node.js

  • Existing Node.js codebases
  • Heavy reliance on Node-specific packages
  • Deployment to platforms without Deno support
  • Teams experienced with Node ecosystem

Fresh framework

Fresh is Deno's full-stack web framework:

deno run -A -r https://fresh.deno.dev

Features:

  • File-based routing
  • Islands architecture (partial hydration)
  • Server-side rendering
  • Zero JavaScript by default
  • Deploy to Deno Deploy
// routes/index.tsx
export default function Home() {
  return (
    <div>
      <h1>Welcome to Fresh</h1>
      <p>A fresh way to build web apps.</p>
    </div>
  );
}

HTTP server example

// server.ts
import { serve } from "https://deno.land/std@0.220.0/http/server.ts";

serve((req: Request) => {
  const url = new URL(req.url);
  
  if (url.pathname === "/api/hello") {
    return Response.json({ message: "Hello from Deno!" });
  }
  
  return new Response("Not Found", { status: 404 });
}, { port: 8000 });

console.log("Server running on http://localhost:8000");
deno run --allow-net server.ts

Deployment

Deno Deploy

Deno's edge hosting platform:

# Install deployctl
deno install -A jsr:@deno/deployctl

# Deploy
deployctl deploy --project=my-project main.ts

Docker

FROM denoland/deno:1.40.0

WORKDIR /app
COPY . .

RUN deno cache main.ts

USER deno
EXPOSE 8000

CMD ["run", "--allow-net", "main.ts"]

Summary

Deno offers a modern JavaScript/TypeScript runtime with:

  1. Native TypeScript without build configuration
  2. Built-in tools for formatting, linting, testing
  3. Secure defaults with explicit permissions
  4. npm compatibility for using existing packages
  5. Fresh framework for full-stack web development

The Deno documentation and Fresh docs have comprehensive guides for getting started.

Frequently Asked Questions

Deno is a JavaScript and TypeScript runtime created by Ryan Dahl (creator of Node.js). It runs TypeScript natively, has built-in tooling, and uses a secure-by-default permission model.

Deno has native TypeScript support, built-in formatter/linter/test runner, URL-based imports, and secure defaults. Node.js has a larger ecosystem and more deployment options. Both can run similar code.

Yes. Deno supports npm packages via npm: specifiers. You can import npm packages directly without node_modules, though some Node-specific packages may not work.

Fresh is a full-stack web framework for Deno. It uses islands architecture for partial hydration, file-based routing, and deploys to Deno Deploy at the edge.

For new projects, Deno is worth considering if you want native TypeScript and built-in tooling. For existing Node.js projects, switching may not be worth the effort unless you need Deno-specific features.

Related Posts