getRuntime.ts•2.71 kB
// https://runtime-keys.proposal.wintercg.org/
export type RuntimeName = 'workerd' | 'deno' | 'netlify' | 'node' | 'bun' | 'edge-light' | '' /* unknown */
/**
 * Indicates if running in Node.js or a Node.js compatible runtime.
 *
 * **Note:** When running code in Bun and Deno with Node.js compatibility mode, `isNode` flag will be also `true`, indicating running in a Node.js compatible runtime.
 */
const isNode = () => globalThis.process?.release?.name === 'node'
/**
 * Indicates if running in Bun runtime.
 */
const isBun = () => !!globalThis.Bun || !!globalThis.process?.versions?.bun
/**
 * Indicates if running in Deno runtime.
 */
const isDeno = () => !!globalThis.Deno
/**
 * Indicates if running in Netlify runtime.
 */
const isNetlify = () => typeof globalThis.Netlify === 'object'
/**
 * Indicates if running in EdgeLight (Vercel Edge) runtime.
 */
const isEdgeLight = () => typeof globalThis.EdgeRuntime === 'object'
/**
 * Indicates if running in Cloudflare Workers runtime.
 * See: https://developers.cloudflare.com/workers/runtime-apis/web-standards/#navigatoruseragent
 */
const isWorkerd = () => globalThis.navigator?.userAgent === 'Cloudflare-Workers'
function detectRuntime(): RuntimeName {
  // Note: we're currently not taking 'fastly' into account. Why?
  const runtimeChecks = [
    [isNetlify, 'netlify'],
    [isEdgeLight, 'edge-light'],
    [isWorkerd, 'workerd'],
    [isDeno, 'deno'],
    [isBun, 'bun'],
    [isNode, 'node'],
  ] as const
  const detectedRuntime =
    runtimeChecks
      // TODO: Transforming destructuring to the configured target environment ('chrome58', 'edge16', 'firefox57', 'safari11') is not supported yet,
      // so we can't write the following code yet:
      // ```
      // .flatMap(([isCurrentRuntime, runtime]) => isCurrentRuntime() ? [runtime] : [])
      // ```
      .flatMap((check) => (check[0]() ? [check[1]] : []))
      .at(0) ?? ''
  return detectedRuntime
}
const runtimesPrettyNames = {
  node: 'Node.js',
  workerd: 'Cloudflare Workers',
  deno: 'Deno and Deno Deploy',
  netlify: 'Netlify Edge Functions',
  'edge-light':
    'Edge Runtime (Vercel Edge Functions, Vercel Edge Middleware, Next.js (Pages Router) Edge API Routes, Next.js (App Router) Edge Route Handlers or Next.js Middleware)',
} as const
type GetRuntimeOutput = {
  id: RuntimeName
  prettyName: string
  isEdge: boolean
}
export function getRuntime(): GetRuntimeOutput {
  const runtimeId = detectRuntime()
  return {
    id: runtimeId,
    // Fallback to the runtimeId if the runtime is not in the list
    prettyName: runtimesPrettyNames[runtimeId] || runtimeId,
    isEdge: ['workerd', 'deno', 'netlify', 'edge-light'].includes(runtimeId),
  }
}