How to Install Deno on RHEL 7

Deno is a modern, secure runtime for JavaScript and TypeScript built on V8 and Rust. Created by Ryan Dahl — the original author of Node.js — Deno was designed to address architectural decisions in Node.js that became pain points over time: no built-in TypeScript support, a complex and mutable node_modules directory, implicit file system and network access, and a non-standard module system. Deno ships as a single executable with TypeScript compilation, a built-in formatter, linter, test runner, and bundler baked in. Its security-first permissions model requires you to explicitly grant access to the file system, network, and environment variables, making it far safer to run untrusted scripts. This tutorial covers installing Deno on RHEL 7, understanding its permissions model, running TypeScript files, and using the Deno task runner and compiler.

Prerequisites

  • RHEL 7 system with a user account (Deno installs per-user, not system-wide by default).
  • curl or wget available: sudo yum install -y curl.
  • Internet access to download the Deno binary from GitHub Releases.
  • Approximately 100 MB of free disk space.
  • Optionally, unzip for manual installation: sudo yum install -y unzip.

Step 1: Install Deno Using the Official Install Script

The simplest installation method is the official shell script, which detects your platform, downloads the correct binary from GitHub Releases, and places it in ~/.deno/bin/:

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

The flags used: -f silently fails on HTTP errors, -s suppresses the progress bar, -S shows errors if the download fails, and -L follows redirects. You will see output confirming the download and installation path:

######################################################################## 100.0%
Archive:  /tmp/deno.zip
  inflating: /root/.deno/bin/deno
Deno was installed successfully to /root/.deno/bin/deno

If the install script is blocked in your environment, you can download the binary manually from GitHub Releases:

DENO_VERSION=$(curl -sI https://github.com/denoland/deno/releases/latest | 
    grep -i location | sed 's/.*tag/v//' | tr -d 'rn')

curl -Lo /tmp/deno.zip 
    "https://github.com/denoland/deno/releases/download/v${DENO_VERSION}/deno-x86_64-unknown-linux-gnu.zip"

mkdir -p ~/.deno/bin
unzip -o /tmp/deno.zip -d ~/.deno/bin
chmod +x ~/.deno/bin/deno

Step 2: Add Deno to Your PATH

The install script prints instructions to add Deno to your shell PATH. Add the following to ~/.bashrc to make deno available in all future sessions:

echo 'export DENO_INSTALL="$HOME/.deno"' >> ~/.bashrc
echo 'export PATH="$DENO_INSTALL/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

Verify the installation:

deno --version
deno 1.44.1 (release, x86_64-unknown-linux-gnu)
v8 12.6.228.3
typescript 5.4.5

Notice that the version output shows not only Deno itself but also the embedded V8 JavaScript engine version and the TypeScript compiler version — both are bundled inside the single deno binary.

Step 3: Run Your First TypeScript File

Create a simple TypeScript file:

cat > ~/hello.ts <<'EOF'
const greeting: string = "Hello from Deno on RHEL 7!";
const year: number = new Date().getFullYear();
console.log(`${greeting} The year is ${year}.`);
EOF

Run it with deno run:

deno run ~/hello.ts
Hello from Deno on RHEL 7! The year is 2024.

Deno compiles and runs TypeScript natively — no separate tsc compiler or ts-node package is required. The first run may take a moment as Deno caches compiled modules; subsequent runs are faster.

Step 4: Understanding Deno’s Permissions Model

One of Deno’s most important features is its security-by-default permissions model. Unlike Node.js, a Deno script cannot access the file system, make network requests, read environment variables, or execute subprocesses unless you explicitly grant permission via command-line flags.

Try running a script that fetches a URL without granting network permission:

cat > ~/fetch_demo.ts <<'EOF'
const response = await fetch("https://httpbin.org/get");
const data = await response.json();
console.log("IP:", data.origin);
EOF

deno run ~/fetch_demo.ts
error: Uncaught PermissionDenied: Requires net access to "httpbin.org", run again with the --allow-net flag

Grant network access with --allow-net:

deno run --allow-net ~/fetch_demo.ts

You can scope permissions to specific hosts:

deno run --allow-net=httpbin.org ~/fetch_demo.ts

Common Permission Flags

  • --allow-net — allow all network access; --allow-net=example.com restricts to specific host
  • --allow-read — allow file system reads; --allow-read=/tmp restricts to a directory
  • --allow-write — allow file system writes
  • --allow-env — allow access to environment variables
  • --allow-run — allow spawning subprocesses
  • --allow-ffi — allow loading dynamic libraries via FFI
  • --allow-all or -A — grant all permissions (use carefully, equivalent to disabling the safety model)

Step 5: Using deno task

Deno has a built-in task runner configured through deno.json (Deno’s project configuration file). This replaces the scripts section of package.json in Node.js projects.

Create a project directory with a deno.json:

mkdir ~/denoapp && cd ~/denoapp

cat > deno.json <<'EOF'
{
  "tasks": {
    "start": "deno run --allow-net --allow-read main.ts",
    "dev": "deno run --watch --allow-net --allow-read main.ts",
    "fmt": "deno fmt",
    "lint": "deno lint",
    "test": "deno test --allow-net"
  }
}
EOF

Create a simple main.ts:

cat > main.ts <<'EOF'
import { serve } from "https://deno.land/[email protected]/http/server.ts";

const handler = (req: Request): Response => {
  return new Response(`Hello from Deno! Path: ${new URL(req.url).pathname}`, {
    status: 200,
    headers: { "content-type": "text/plain" },
  });
};

console.log("Listening on http://localhost:8000");
await serve(handler, { port: 8000 });
EOF

Run the task:

deno task start

The --watch flag in the dev task causes Deno to automatically restart when source files change — ideal for development.

Step 6: Compile to a Standalone Executable with deno compile

Deno can package a script and the Deno runtime into a single self-contained executable binary — useful for distributing CLI tools:

deno compile --allow-net --output /usr/local/bin/myserver main.ts

The resulting binary has no runtime dependency on Deno being installed:

/usr/local/bin/myserver
Listening on http://localhost:8000

For cross-compilation to different targets (e.g., compiling on RHEL 7 for macOS):

deno compile --target x86_64-apple-darwin --allow-net --output myserver-macos main.ts

Step 7: Deno vs Node.js — Key Differences

  • TypeScript support: Deno runs .ts files natively; Node.js requires tsc or ts-node.
  • Module system: Deno uses ES modules with URL imports (import { serve } from "https://..."); Node.js uses CommonJS (require()) by default, with ESM support added later.
  • No node_modules: Deno caches modules globally in ~/.cache/deno; there is no per-project node_modules directory.
  • Security: Deno denies all I/O by default; Node.js grants full access implicitly.
  • Built-in tools: Deno ships with a formatter (deno fmt), linter (deno lint), test runner (deno test), bundler (deno bundle), and doc generator (deno doc) — no external tooling required.
  • npm compatibility: Deno 1.28+ supports npm: specifiers, allowing many npm packages to be used: import express from "npm:express".

Step 8: Updating Deno

Deno has a built-in self-update command:

deno upgrade

To upgrade to a specific version:

deno upgrade --version 1.44.0

To switch to the canary (nightly) channel:

deno upgrade --canary

Deno is now fully installed and operational on your RHEL 7 system. Its single-binary distribution, built-in TypeScript support, and security-first permissions model make it an attractive runtime for scripts, API servers, and CLI tools that benefit from compile-time safety and controlled resource access. The absence of a node_modules directory and the built-in toolchain (formatter, linter, test runner, compiler) reduce project setup friction significantly compared to equivalent Node.js workflows. As Deno’s npm compatibility layer continues to mature, it becomes increasingly viable as a drop-in successor for many Node.js use cases while offering a substantially improved security posture.