Table of contents
Node.js popularised the concept of running JavaScript on the server. There are more JavaScript runtimes intended for building server-based applications today, with Bun and LLRT being the most recent I'm aware of. Some of these runtimes have adopted Web Platform APIs to allow the same API to be used both in the browser and the server (e.g. web crypto API), however, they also have runtime-specific APIs.
You might want to check if your code is running on a specific runtime before using its unique API. Perhaps the runtime behaves differently for certain operations, and you want to check if you're running in the right runtime before executing a block of code.
But how can you do that? It turns out there are various ways, both good and hacky.
The Secret Sauce 🤫
The right way to know what runtime your code runs on is to use navigator.userAgent
. It returns a string containing the runtime and optionally the runtime's version.
You might be familiar with this API from the browser spec, as a way to determine the browser your code runs on. Although browser detection using this approach is not recommended, the WinterCG group has agreed on this as part of their minimum Common Web Platform API for Non-Browser ECMAScript-based runtimes.
Here's an example of the result you get when running this in different runtimes:
runtime | result |
Node.js | Node.js/22 |
Bun | Bun/1.0.28 |
Cloudflare Workers | Cloudflare-Workers |
Deno | Deno/1.40.0 |
The Wrong Way ❌
Before now, there are various ways I've seen or read on how to do this. For example, this code was suggested on Stackoverflow as a way to check if it's running on Deno:
if ("Deno" in window) {
console.log("window.Deno=", window.Deno);
} else {
console.log("no Deno here");
}
There are API-specific hacks that look like one of these:
function isNode() {
try {
const fs = await import('fs');
return true;
} catch () {
return false;
}
}
function isNode() {
try {
const env = process.env;
return true;
} catch () {
return false;
}
}
The problem with that approach is that now that Cloudflare supports process.env
, code that used to work reliably would no longer work.
Conclusion
In this article, we explore how to determine the runtime environment for JavaScript code, especially with the advent of modern runtimes like Bun and Deno. The recommended approach is to use navigator.userAgent
, which provides a string identifying the runtime and optionally its version. The WinterCG group endorses this method as part of their minimum Common Web Platform API.
We also discussed less reliable methods, such as checking for specific global objects or APIs, which can lead to inaccuracies due to overlapping capabilities among different runtimes.