Deno is a modern runtime for JavaScript and TypeScript built by Ryan Dahl, the original creator of Node.js. It addresses several design decisions in Node that aged poorly – dependency management, security defaults, and TypeScript support. Deno runs TypeScript natively without a build step, enforces a permissions-based security model, and ships as a single binary with built-in tooling. This guide covers installing Deno on RHEL 10 and Ubuntu 24.04, running your first TypeScript program, and understanding how it compares to Node.js.
What Is Deno
Deno is a JavaScript/TypeScript runtime built on V8 (the same engine Chrome and Node.js use) with Rust providing the system-level bindings. Key differences from Node.js include:
- TypeScript first: Runs .ts files directly without tsc or a bundler
- Secure by default: No file, network, or environment access unless explicitly granted
- No node_modules: Dependencies are URLs, cached globally
- Built-in tooling: Formatter, linter, test runner, and bundler included
- Web standard APIs: Uses fetch(), Web Streams, and other browser APIs instead of Node-specific ones
- Node compatibility: Recent versions include a Node.js compatibility layer for importing npm packages
Install Deno on RHEL 10
Deno distributes as a single binary, making installation straightforward on any Linux distribution. The official install script downloads the latest release:
curl -fsSL https://deno.land/install.sh | sh
This installs Deno to ~/.deno/bin/deno. Add it to your PATH by appending to your shell profile:
echo 'export DENO_INSTALL="$HOME/.deno"' >> ~/.bashrc
echo 'export PATH="$DENO_INSTALL/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Verify the installation:
deno --version
You should see output showing the Deno version, V8 version, and TypeScript version bundled with the runtime.
Alternatively, if you prefer package manager installation on RHEL 10, you can use snap:
sudo dnf install -y snapd
sudo systemctl enable --now snapd.socket
sudo snap install deno
Install Deno on Ubuntu 24.04
The same install script works on Ubuntu:
curl -fsSL https://deno.land/install.sh | sh
Add to PATH (for bash):
echo 'export DENO_INSTALL="$HOME/.deno"' >> ~/.bashrc
echo 'export PATH="$DENO_INSTALL/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc
Or install via snap on Ubuntu (snapd is pre-installed):
sudo snap install deno
Verify the installation:
deno --version
Run TypeScript Directly
One of Deno’s strongest features is running TypeScript without any compilation step. Create a file called hello.ts:
interface ServerInfo {
hostname: string;
port: number;
uptime: string;
}
const info: ServerInfo = {
hostname: Deno.hostname(),
port: 8080,
uptime: "3 days",
};
console.log(`Server: ${info.hostname}`);
console.log(`Port: ${info.port}`);
console.log(`Uptime: ${info.uptime}`);
Run it:
deno run --allow-sys hello.ts
Notice the --allow-sys flag – Deno requires it because Deno.hostname() accesses system information. Without the flag, the program fails with a permission error. This is the security model in action.
Understanding the Permissions Model
Deno runs with no permissions by default. Your code must be explicitly granted access to system resources. The key permission flags are:
--allow-read– Read files from disk (optionally restricted to specific paths)--allow-write– Write files to disk--allow-net– Make network requests (optionally restricted to specific domains/ports)--allow-env– Access environment variables--allow-run– Execute subprocesses--allow-sys– Access system information (hostname, OS, memory)--allow-allor-A– Grant all permissions (use only in development)
Permissions can be scoped. For example, allow network access only to a specific API:
deno run --allow-net=api.example.com app.ts
Or allow file reads only from a specific directory:
deno run --allow-read=/etc/myapp app.ts
This model prevents supply-chain attacks where a compromised dependency tries to read your SSH keys or phone home to a remote server.
Configure Projects with deno.json
For projects beyond a single script, create a deno.json configuration file in the project root:
{
"tasks": {
"dev": "deno run --watch --allow-net --allow-read main.ts",
"start": "deno run --allow-net --allow-read main.ts",
"test": "deno test --allow-read",
"lint": "deno lint",
"fmt": "deno fmt"
},
"imports": {
"std/": "https://deno.land/[email protected]/",
"oak": "https://deno.land/x/[email protected]/mod.ts"
},
"compilerOptions": {
"strict": true
}
}
The tasks section defines scripts similar to npm scripts. Run them with:
deno task dev
deno task test
The imports section creates import aliases (an import map), so instead of writing full URLs in every file, you write:
import { Application } from "oak";
Verify your configuration is valid:
deno info
Using npm Packages in Deno
Deno supports importing npm packages directly using the npm: specifier. This means you can use most of the npm ecosystem without switching runtimes:
import express from "npm:express@4";
const app = express();
app.get("/", (_req, res) => {
res.json({ runtime: "deno", status: "running" });
});
app.listen(3000, () => {
console.log("Server running on http://localhost:3000");
});
Run it with network permissions:
deno run --allow-net --allow-read --allow-env server.ts
Verify by opening http://localhost:3000 in a browser or with curl.
Deno vs Node.js – Practical Comparison
Here is how the two runtimes stack up in day-to-day usage:
| Feature | Node.js | Deno |
|---|---|---|
| TypeScript | Requires tsc or ts-node | Native, zero config |
| Package management | npm/yarn with node_modules | URL imports, global cache |
| Security | Full system access by default | No access unless granted |
| Linting/Formatting | Install ESLint, Prettier | Built-in (deno lint, deno fmt) |
| Testing | Install Jest, Mocha, etc. | Built-in (deno test) |
| npm compatibility | Native | Via npm: specifier (good, not perfect) |
| Ecosystem size | Massive | Growing, plus npm compat |
| Production maturity | 15+ years | Maturing rapidly |
Node.js remains the safer choice for large production applications with complex dependency trees. Deno shines for new projects, scripts, CLI tools, and situations where security isolation matters. The npm compatibility layer makes migration easier than it was in Deno’s early days.
Wrapping Up
Deno offers a cleaner developer experience than Node.js for TypeScript-heavy projects, with security defaults that make sense for modern deployments. Installation is a single command on both RHEL 10 and Ubuntu 24.04, the permissions model protects against supply-chain attacks, and deno.json gives you project configuration without the sprawl of package.json, tsconfig.json, and .eslintrc. If you are starting a new project or building internal tooling, Deno is worth serious consideration.




























































