/commands/deno/deno-add-npm-package
deno add npm:package: add an npm or JSR dependency to a Deno project
- tool
- Deno
- versions
- Deno 2.x
- os
- any
deno add npm:express adds an npm package to a Deno project, and deno add jsr:@std/path adds a package from JSR. Deno writes the dependency to the imports map of deno.json (creating the file if needed), records the exact resolved version in deno.lock, and downloads the package, so code can then import it by its bare name: import express from "express".
Add a package
export NO_COLOR=1
npx --yes deno@2 add npm:is-odd@3 2>&1 | grep -E "^(Created|Add)"
cat deno.json
cat > main.ts <<'EOF'
import isOdd from "is-odd";
console.log(isOdd(7));
EOF
npx --yes deno@2 run main.tsOutput
Created deno.json configuration file.
Add npm:is-odd@3.0.1
{
"imports": {
"is-odd": "npm:is-odd@^3.0.1"
}
}
trueDeno resolved is-odd@3 to the newest 3.x release and stored a caret range (^3.0.1) in the import map, so later lock refreshes stay within 3.x. The example runs Deno through npx deno@2 so it needs only Node.js; with Deno installed the commands are deno add and deno run.
In a project with package.json
export NO_COLOR=1
echo '{ "name": "app", "private": true }' > package.json
npx --yes deno@2 add npm:is-odd@3.0.1 2>&1 | grep -E "^(Created|Add)"
cat package.json
ls -d node_modulesOutput
Add npm:is-odd@3.0.1
{
"name": "app",
"private": true,
"dependencies": {
"is-odd": "3.0.1"
}
}
node_modulesWhen the folder has a package.json and no deno.json, Deno adds npm packages to its dependencies, like npm install, and installs them into node_modules. This keeps the project usable by Node.js tools too. With an exact version the entry is exact; with a range or no version Deno writes a caret range.
Variants
| Command | What it does |
|---|---|
| deno add npm:express | Latest version from npm, saved as ^x.y.z |
| deno add npm:express@4 | Newest 4.x release |
| deno add jsr:@std/assert | A package from the JSR registry |
| deno add jsr:@std/path npm:chalk | Several packages in one command |
| deno add --dev npm:vitest | devDependencies in package.json; with deno.json the entry goes to imports as usual |
| deno add npm:@types/node | Scoped npm packages work the same way |
| deno remove npm:is-odd | Removes the entry from deno.json or package.json |
| deno install | Installs everything listed, for example after a fresh clone |
Pitfalls
- Missing prefix. Current Deno 2 releases accept a bare name (
deno add is-oddwas recorded asnpm:is-odd), but older 2.x releases require the prefix, and a name can exist on both registries. Writenpm:orjsr:to say which package you mean. - Imports without an entry. Importing a bare name that is not in the import map fails with Import "x" not a dependency;
deno addis the fix. - Lock file conflicts.
deno.lockpins the exact versions. Commit it, and run CI with--frozen-lockfile(for exampledeno install --frozen-lockfile) to fail when it would change.
How to confirm it worked
cat deno.json (or package.json) shows the new entry, deno.lock contains the resolved version, and deno run main.ts runs without asking for the package again. deno info main.ts prints the dependency graph of a file with the version that was used.
FAQ
Do I need deno add to use an npm package?
No. You can import npm:package@version directly in code. deno add puts the version in one place (the import map in deno.json or package.json) so every file can use the bare name and the version is updated in one line.
Does deno add create node_modules?
Only when the project uses a package.json, or when nodeModulesDir is set in deno.json. With a plain deno.json, npm packages are kept in the global Deno cache and no node_modules folder appears.
How do I upgrade a package added with deno add?
Run deno add again with the new version, or use deno outdated to list newer versions and deno outdated --update to bump them.