Using Lodash with Deno's Strict Module Resolution

Deno enforces strict, browser-compatible module resolution that requires explicit file extensions, full URLs, and standard ECMAScript Modules (ESM). Because Lodash was originally designed for Node.js’s implicit CommonJS module system, running it in Deno requires bridging these architectural differences. This guide explains how Lodash integrates with Deno using modern ESM CDNs, native npm: specifiers, and import maps to satisfy Deno’s resolution engine.

The Compatibility Challenge

Node.js allows implicit module resolution—such as resolving require('lodash') to a local node_modules directory and automatically locating an index.js file. In contrast, Deno does not look into a local node_modules folder by default, nor does it automatically infer file extensions or directory indexes. Deno requires fully qualified URLs or explicit relative file paths terminating with an extension (such as .js or .ts). Because the standard lodash package relies on CommonJS, integrating it requires formats that Deno can statically parse.

Method 1: Using the Native npm: Specifier

The most modern and straightforward method to integrate Lodash into Deno is via the native npm: protocol. Deno includes built-in compatibility for npm packages, handling module resolution and CommonJS-to-ESM translation automatically in a managed cache.

To import the standard CommonJS version:

import _ from "npm:lodash@^4.17.21";

const numbers = [1, 2, 3, 4, 5];
console.log(_.chunk(numbers, 2));

For better tree-shaking and native ESM execution, use lodash-es:

import { chunk, compact } from "npm:lodash-es@^4.17.21";

console.log(chunk([1, 2, 3, 4], 2));

Using npm: bypasses the need for external CDNs while strictly adhering to Deno's resolution syntax. Deno downloads the package to a global cache, resolves dependencies, and exposes the module interface.

Method 2: Using ESM CDNs

Before native npm resolution was introduced, ESM CDNs emerged as the standard way to load third-party libraries in Deno. CDNs such as esm.sh rewrite CommonJS packages into standard ES modules on the fly, adding necessary file extensions to satisfy Deno's strict URL loading rules.

import _ from "https://esm.sh/lodash-es@4.17.21";

const data = [0, 1, false, 2, "", 3];
console.log(_.compact(data));

You can also import individual utilities to reduce bundle overhead:

import debounce from "https://esm.sh/lodash-es@4.17.21/debounce";

CDNs inspect the incoming request headers from Deno and serve an ESM wrapper alongside appropriate X-TypeScript-Types headers, ensuring both runtime compatibility and static type checking without manual configuration.

Method 3: Simplifying Imports with Import Maps

Repeating npm: specifiers or full CDN URLs throughout a project makes refactoring tedious. Deno allows you to normalize these imports using an import map defined inside deno.json or deno.jsonc.

Configure your deno.json:

{
  "imports": {
    "lodash": "npm:lodash-es@^4.17.21",
    "lodash/": "npm:lodash-es@^4.17.21/"
  }
}

Once configured, your application files can use standard bare specifiers:

import { shuffle } from "lodash";
import sortBy from "lodash/sortBy.js";

const items = [3, 1, 2];
console.log(shuffle(items));
console.log(sortBy(items));

This approach combines the clean syntax of traditional JavaScript ecosystems with the strict resolution requirements enforced by Deno's runtime.