Knowledge Hub
In the hope that our children will surpass us, we try to protect them from our own mistakes and give them a better life. This sentiment mirrors Ryan Dahl's intentions when he developed Deno. Deno is often seen as the successor to Node. While many developers pit these runtimes against each other, it's an unfair comparison, as Deno was born out of Ryan's reflections on how he might have enhanced the module system, ensured stable legacy APIs, and bolstered security in Node.
It’s been three years since the emergence of Deno, and this JavaScript runtime has found its place in the development environment and the hearts of developers for its added features improvement. In this article, we will explore those features.
I will strongly advise you to have a decent grasp of JavaScript and Node.js runtime environments, and module systems as this would be helpful to grasp the concepts and comparisons discussed in this article.
Deno provides convenient scripts to download and install despite the variance of operating systems. Below are various installations available for different OS, these installations are obtained from Deno’s official Docs.
Using Shell (macOS and Linux):
curl -fsSL https://deno.land/x/install/install.sh | sh
Using PowerShell (Windows):
irm https://deno.land/install.ps1 | iex
Using Winget (Windows):
winget install --id DenoLand.Deno -e
Using Scoop (Windows):
scoop install deno
Using Chocolatey (Windows):
choco install deno
Using Homebrew (macOS):
brew install deno
Using MacPorts (macOS):
sudo port install deno
Using Nix (macOS and Linux):
nix-shell -p deno
To install Deno from Git directly you can use asdf (macOS and Linux):
asdf plugin-add deno https://github.com/asdf-community/asdf-deno.git
asdf install deno latest
# To install globally
asdf global deno latest
# To install locally (current project only)
asdf local deno latest
Once the command appropriate for your operating system has been executed, the Deno CLI binary will be installed on your computer. After the success message in the terminal, run deno
and you should have this in your terminal:
C:\Users\Hp>deno
Deno 1.36.3
exit using ctrl+d, ctrl+c, or close()
REPL is running with all permissions allowed.
To specify permissions, run `deno repl` with allow flags.
>
// This confirms the installation by displaying the version in the terminal
To confirm the version that has been installed, run Deno --version
. This command when executed should print the version type, followed by the Typescript version.
C:\Users\Hp>Deno --version
deno 1.36.4 (release, x86_64-pc-windows-msvc)
v8 11.6.189.12
typescript 5.1.6
To confirm the latest version, go to Deno’s site, and if it matches what has been downloaded here, begin your journey. If it doesn’t, you can simply run this command in your CLI:
C:\Users\Hp>deno upgrade
Looking up latest version
Found latest version 1.36.4
Downloading https://github.com/denoland/deno/releases/download/v1.36.4/deno-x86_64-pc-windows-msvc.zip
\[00:14\] [-----------------------------------------------------------------]
After installation, run Deno --version
, and you should have the latest version. As of the time of writing this article, the latest version of Deno was version 1.36.4
.
Deno was created by an American software engineer Ryan Dahl (born 1981), best known for creating the Node.js JavaScript runtime. Deno is all about making JavaScript on the server feel like JavaScript in the browser. It supports JavaScript, TypeScript, and WebAssembly. If you've bounced between Node and browser-based JavaScript, you've seen the API differences. Deno's goal is to smooth that out, giving you familiar browser-like APIs even on the server side.
Imagine Deno as a new kind of smartphone. Older phones (let's say, Node.js in this analogy) are functional and widely used, but you need to download lots of apps (third-party tools) to get all the features you want.
Deno, on the other hand, comes with many of those essential features built-in, like a better camera or a built-in flashlight, so you don't need to clutter it with extra apps, and these features are made available on every update. Plus, it has enhanced security features, like a top-notch fingerprint scanner, ensuring only approved actions are taken.
Deno has incredible features, but the five picked in this article to be discussed, are where it glitters the most.
Typescript is the superset of JavaScript that compiles to plain JavaScript. If you are not familiar with Typescript, the image will give you an overview of what Typescript is and brings.
Let’s imagine JavaScript is like your favorite book. It's fun and engaging, and you can read it over and over. But sometimes, you might get a bit lost in the plot twists, ambiguous words, or the characters' motives, and as a little help, the author puts helpful notes where he feels his readers could get lost. Now, think of TypeScript as that same book, but with helpful notes in the margins.
Typescript specifies the data type being passed around a code, and when it picks an unmatched type it reports an error to the developer, This is so helpful and allows developers to write clean and easily debugged codes.
Unlike Node where you need a few configurations to get Typescript up and running, Deno offers built-in TypeScript support. This means you don't need any external tools or configurations to run TypeScript code. Let’s take a code example:
// greet function:
// Takes in a name.
// Returns a friendly greeting message using that name, saying "Hey there, [name]! It's great to see you."
function greet(name: string): string {
return `Hey there, ${name}! It's great to see you. Hope you're having an awesome day!`;
}
// TwistGreeting function:
// Also takes in a name as an input.
// Flips the name backward (e.g., "KEN" becomes "NEK").
// Returns a message showing the name in this reversed form, saying "Just for fun, your name backward.
function twistGreeting(name: string): string {
let twistedName = name.split('').reverse().join('');
return `Just for fun, your name backwards is: ${twistedName}`;
}
console.log(greet("Bejamas"));
console.log(twistGreeting("Bejamas"));
console.log(greet("Marvel ken"));
console.log(twistGreeting("Marvel ken"));
The result:
That’s how Typescript is used in Deno. moving on we will be using only TypeScript.
One of the significant functions of Deno is its ability to import modules directly from a URL. It reduces the complexity of starting a new project or setting up a development environment. This also gives room for better performance. Once a module is downloaded, Deno caches it resulting in faster script execution. Importing from a URL seems to be safer as it reduces the risk of "dependency hole" where a module might have hidden or unexpected dependencies that could pose a security threat.
Let’s look at an example below;
import { serve } from "https://deno.land/std@0.76.0/http/server.ts";
const URL = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of URL) {
req.respond({ body: "Bejamas and Marvel " });
}
The serve function is imported directly from Deno's library in our code example above. You can specify the version of the module, ensuring that your application doesn't break due to updates. Run the code using deno run test.ts
.
We have this rendered in our browser:
By default, Deno runs in a sandbox, and when you execute the script, it doesn't have permission to the file system or network. Your computer is like your home. Inside are different rooms like the kitchen, bedrooms, and living room. Each room has its own purpose. Similarly, your computer has different functions, like accessing files and many more.
Imagine your rooms and kitchen do have doors but no keys. It gives a huge opportunity for unauthorized guests to overstep your boundaries and ruin your privacy. In a programming environment, some apps or scripts act like guests coming into your home and having the freedom to wander around your house, which is not very private.
With Deno, it's like your home suddenly has doors with locks and keys. If a guest who is likened to a “script” wants to enter a room that is likened to “using a function on your computer”, they need to ask for permission first. Now, Deno has flags for accessing different things, more like you give permissions for whatever a guest would want to do in your house.
They may ask "Hey, can I at least get bread from the fridge (read a file)?".
You, as the homeowner, get to decide - "Sure, but just the fridge. Stay out of my bedroom!"(using the flag). This way, the guest (in this analogy a script) sticks to only what they have permission for.
Now you have control over what each guest can or cannot do in your home. It's a more secure and transparent way to handle things, ensuring no sneaky guests are going through your personal stuff without you knowing.
Let’s take a look at the flags Deno supports and what they handle. We will need this information from the official docs, and then we can try out a few examples to wrap our hands around it.
Deno Flags | Permissions |
---|---|
–allow-env= | It allows environment access for things like getting and setting environment variables. |
–allow-sys= | It allows access to APIs that provide information about the user’s operating system. |
–allow-hrtime | It allows high-resolution time measurement. |
-A, –allow-all | It enables all security-sensitive functions. Use with caution. |
–deny-write= | It denies file system write access. |
–Allow-read= | It allows file system read access. |
–deny-env= | It denies environment access for things like getting and setting of environment variables. |
–allow-write= | It allows file system write access. |
The table above contains information obtained from the official Docs.
// example1.ts
console.log("Home Directory:", Deno.env.get("USERPROFILE"));
// For Windows
// Run this command using deno run --allow-env=USERPROFILE example1.ts
// example2.ts
// --allow-read Read file content and output
const text = await Deno.readTextFile("./text.txt");
console.log(text);
The –allow-hrtime
can be used in timing attacks and fingerprinting.
// example3.ts
const start = performance.now();
// Simulating some code that takes time
await new Promise(resolve => setTimeout(resolve, 1000)); // Delay for 1 second
const end = performance.now();
console.log(`Elapsed time: ${end - start} milliseconds`);
We have been able to look at a few examples of what permissions bring to the table.
In Node and other JavaScript environments, await is not usually welcome outside an async function. Here is an example of what I mean:
// Without top-level await, you would have to wrap code in an async function
async function main() {
let response = await fetch("https://api.Bejamas.com");
let fetchedData = await response.json();
console.log(fetchedData);
}
main();
However, with Deno, await can be used outside, and this is how Deno handles this.
Deno introduces the concept of a Top-level await
, which welcomes await
to be used at the top-level of a module. It doesn’t prevent you from using Async but it doesn't necessitate it either.
Here is an example of how Deno uses it:
// Deno Top-Level await
let response = await fetch("https://api.Bejamas.com/data");
let fetchedData = await response.json();
console.log(fetchedData);
In the standard library, we have all the libraries created and managed by the Deno core team. It’s a comprehensive library that covers a wide range of functionalities. If you open any package, you can see how to import and use any of the packages.
Deno advises that the standard library is not yet stable. Therefore, it is versioned differently than Deno. It is also strongly advised to always use imports with pinned versions of the standard library to avoid potentially causing compilation errors or unexpected behavior.
Instead of doing this:
// ❌ import the latest release, this should be avoided
import { copy } from "https://deno.land/std/fs/copy.ts";
Do this:
// ✅ imports from v0.201.0 of std, never changes
import { copy } from "https://deno.land/std@0.201.0/fs/copy.ts";
The codes above were obtained from Deno's official docs.
Node is a back-end Javascript open-source server environment that operates on the v8 engine. It can run on several operating systems. Node.js is often used by developers on the server side and in generating dynamic web pages. It confirms why JavaScript is popular and powerful as it can be used almost everywhere (back end and front end). A large number of companies use Node.js, these are the likes of Netflix, Uber, PayPal, Medium, Trello, and many more.
Let’s explore the key features of using Node.js.
Node.js has a non-blocking system, where it doesn’t wait for an API to return any data, before moving on to the next. When it asks for some data or performs an action, it doesn't sit idle waiting for the result. Instead, it continues to work on other tasks. Once the data is ready or the action is complete, Node.js is informed through a system of notifications. This approach allows Node.js to handle many operations at the same time, making it efficient.
Node runs on the JavaScript v8 engine. V8 is well known for its high-level performance and makes Node.js very fast in code execution.
Node Package Manager provides a library of reusable modules and packages, making it much easier for developers to add more functionalities to their projects.
Node.js works in a unique way in that it uses a single-threaded model and event looping. It means that although it processes tasks one at a time, it doesn't wait around. Instead, it keeps moving to the next task, making it efficient at handling many tasks at once, allowing developers to manage a lot of activities simultaneously. Node.js can serve many more requests with the same resources, making it a more efficient choice for many developers.
Node.js is backed by a great community that always tries to make it better, so much gratitude to this dedicated community, as we get to see frequent updates, new modules, and quick solutions to certain issues. It is also important to note that Node.js is released under the MIT license.
These runtimes will be compared on certain criteria which are:
Deno and Node were built on the V8 JavaScript engine and are designed for high performance, especially in asynchronous I/O operations. Deno was developed using Rust, whereas Node.js was developed using c/c++ and this contributes to their great performance.
In Node.js, npm is used to install packages and manage a project's dependencies. These packages are normally stored in Node modules, and there is a package.json
file used to track and specify which packages.
On the other hand, Deno doesn't take a totally different approach as it also supports npm. However, instead of totally relying on NMP, Deno allows you to import packages directly from URLs. When you import a package, it is cached in your hard drive. It means that if you need to use the same package in another part of your project or a different project, you don't have to download it again. Deno will use the cached copy.
Deno places a strong emphasis on security. When you run a program in Deno, it's confined to a secure environment, which limits its access to the file system, network, environment variables, and execution of other scripts. Accessing these resources requires permissions. It means that when you execute a script in Deno, you need to provide specific flags to grant it permissions for these operations, as we have earlier discussed.
On the other hand, Node.js provides scripts with default access to the file system and network. While this offers ease of development, it can introduce a lot of potential security challenges.
Deno embraces ES modules, allowing you to use imports similar to how you would in vanilla JavaScript or React. It brings two main benefits over the Node.js traditional require
system. First, whereas require
loads resources in a synchronous manner, ES modules use asynchronous imports, leading to better performance. Second, with ES modules, you can selectively import just the parts of a package you need, which is more efficient and saves memory.
Deno is gaining popularity with a rising number of GitHub stars and contributors. People like its security features, built-in tools, and fresh take on JavaScript runtime. Meanwhile, Node.js has been there for a decade with a huge community and a lot of libraries. While Node.js has a well-established ecosystem, Deno is trying to catch up.
In Deno, you can use the browser APIs, like fetch
, without installing any extra packages. In Node, you'd typically install something like the node-fetch
package for this. With Deno, you also get native access to window objects, making your code cleaner with fewer package dependencies.
Deno has TypeScript built-in. Just save your files with a .ts
extension and you're able to use TypeScript. No extras, as we have earlier discussed. In Node.js, despite you being able to use TypeScript, you'd need to install it and set up a TS config. It's a bit more stressful.
Deno comes with built-in tools like a code formatter (deno fmt), a linter (deno lint), a test runner (deno test), and a language server for your editor, making development smoother without needing extra tools. In contrast, Node.js developers often turn to external tools like Prettier for these tasks.
Whether to choose Deno over Node.js, or vice versa, is a decision I'll leave in your hands after going through this article. The key is to select the one that best fits your project's requirements. If you're after a well-established JavaScript runtime with vast solutions across the web, Node might be the way to go. However, if you're familiar with TypeScript and prioritize security, Deno could be your pick. Currently, Deno's main challenge is its still-growing developer community. Thank you so much for sticking with this piece. Keep on coding!