deno pack
The deno pack command builds an npm-compatible tarball (.tgz) from a Deno project, so you can publish a Deno-authored library straight to the npm registry. It transpiles TypeScript to JavaScript, generates .d.ts declaration files, rewrites import specifiers, and synthesizes a package.json that npm-only consumers can understand.
deno pack is not equivalent to npm pack. It's a build step that converts a Deno/JSR project into an npm-publishable package — closer to deno transpile plus npm pack combined. It does not read an existing package.json, does not honor .npmignore, and does not run prepublishOnly / prepare lifecycle scripts.
Quick start
deno pack
deno pack reads the package metadata from deno.json (the name, version, and exports you'd use to publish to JSR) and writes a gzipped tarball to the current directory.
Given a deno.json like:
{
"name": "@scope/my-lib",
"version": "1.0.0",
"exports": "./mod.ts"
}
deno pack produces scope-my-lib-1.0.0.tgz (the @ is stripped and / becomes -, matching npm pack's naming convention).
What's in the tarball
| Contents |
|---|
A generated package.json with name, version, type: "module", conditional exports (types / import / default), and a dependencies field derived from your jsr: / npm: imports. |
Transpiled .js files (with inline source maps by default; pass --no-source-maps to omit). |
Generated .d.ts declaration files (produced via the same fast-check pipeline as deno publish). |
README and LICENSE files from the project root, if present. |
Only files reachable through the module graph from exports are included. Non-JS assets such as data files or WASM are only included if they're imported from JS/TS. If you need to ship arbitrary files, list them as positional arguments:
deno pack assets/icon.svg locales/*.json
Specifier rewriting
For the generated package to work on Node and other npm consumers, deno pack rewrites imports as it transpiles:
| In your source | In the tarball | Notes |
|---|---|---|
jsr:@std/path | @jsr/std__path | Consumers need the JSR npm registry configured. |
npm:express@4 | express | Version moves into dependencies in package.json. |
./utils.ts | ./utils.js | Extension only — no path restructuring. |
node:fs | node:fs | Unchanged. |
Because JSR imports turn into @jsr/... specifiers, anyone installing the published tarball needs the JSR npm registry configured. The simplest way is to run npx jsr add once in the consumer project; that sets up the .npmrc entries for the @jsr scope.
Deno API shimming
If your code uses the Deno.* global, deno pack adds @deno/shim-deno as a runtime dependency and injects the shim so the package can run under Node.js. The shim covers the subset of Deno.* that maps cleanly onto Node APIs — review the shim's docs to see what's polyfilled.
Pass --no-deno-shim to opt out, e.g. if you've already provided your own abstraction or only intend the package to run under Deno-on-npm.
Publishing to npm
deno pack
npm publish ./scope-my-lib-1.0.0.tgz
A typical release flow:
# 1. Bump the version
deno bump-version patch
# 2. Build the tarball
deno pack
# 3. Verify the contents (extracted view)
tar -tzf scope-my-lib-1.0.0.tgz
# 4. Push to npm
npm publish ./scope-my-lib-1.0.0.tgz
For JSR releases, use deno publish instead — deno pack is specifically for the npm registry.
Workspace support
In a workspace, deno pack runs against the current working directory's member. To pack a specific member from the root:
cd packages/my-lib
deno pack
Cross-workspace npm: / jsr: dependencies are rewritten in the generated package.json to point at their published versions, not to other workspace members — make sure those dependencies have been released independently before publishing your tarball.
Examples
Override the version
Useful when releasing a one-off prerelease without editing deno.json:
deno pack --set-version 2.0.0-rc.1
Pick the output path
deno pack --output dist/my-package.tgz
Preview without writing
deno pack --dry-run
--dry-run prints what would be in the tarball without producing one — handy in CI to verify file inclusion rules.
Allow slow types
Slow types prevent .d.ts generation. Pass --allow-slow-types to pack anyway; the tarball will not include declaration files.
deno pack --allow-slow-types
Skip the Deno shim
deno pack --no-deno-shim
Pack despite a dirty working tree
deno pack --allow-dirty
By default deno pack refuses to pack when the git working tree has uncommitted changes, to make releases reproducible from the commit hash.
Exclude files
deno pack --ignore=tests/ --ignore='**/*.test.ts'
--ignore accepts glob patterns. Combine multiple --ignore flags to add patterns.
Omit source maps
deno pack --no-source-maps
By default, source maps are inlined in the emitted .js files. Use --no-source-maps to strip them — smaller tarballs, but harder to debug upstream.
Limitations
-
No
binentries.deno packdoes not synthesize thepackage.jsonbinfield. Library publishing is supported; CLI tools that need anode-shebanged executable still need a hand-rolled npm package. -
No native addons. Packages that link against native code or ship a
node-gypbuild step are out of scope. -
No
.npmignore. Use--ignorefor excludes;.gitignoreis honored for what's considered part of the project. -
No lifecycle scripts.
prepublishOnly/prepare/postinstallhooks from a hand-writtenpackage.jsonare not run because thepackage.jsonis generated, not read.
When to use deno pack vs deno publish
| Need | Use |
|---|---|
| Release to JSR | deno publish |
| Release the same library to npm |
deno pack → npm publish ./*.tgz
|
| Reach Node-only consumers without forcing JSR setup |
deno pack (rewrites JSR imports for them) |
A library can ship to both — release to JSR with deno publish, then build and push a tarball to npm with deno pack for users who haven't adopted JSR yet.
See also
-
deno publish— release to JSR -
deno transpile— the emit step thatdeno packuses internally -
deno bump-version— bumpversionindeno.json/package.jsonbefore packing - Publishing modules — overview of where Deno-authored libraries can be published
deno pack [OPTIONS] [files]...Create an npm-compatible tarball from a Deno project
Options
--allow-dirtyAllow packing if the repository has uncommitted changes.
--allow-slow-typesSkip fast-check type extraction; .d.ts files are omitted from the output.
--config, -c<FILE>
Configure different aspects of deno including TypeScript, linting, and code formatting. Typically the configuration file will be called deno.json or deno.jsonc and automatically detected; in that case this flag is not necessary.
--dry-runShow what would be packed without creating the tarball.
--env-file<FILE>optional
Load environment variables from local file Only the first environment variable with a given key is used. Existing process environment variables are not overwritten, so if variables with the same names already exist in the environment, their values will be preserved. Where multiple declarations for the same environment variable exist in your .env file, the first one encountered is applied. This is determined by the order of the files you pass as arguments.
--ignore<ignore>
Ignore files matching these patterns.
--no-configDisable automatic loading of the configuration file.
--no-source-mapsDon't include source maps in the output.
--output, -o<FILE>
Output file path (defaults to
--set-version<VERSION>
Override the version in the tarball.
Last updated on
© 2018–2025 the Deno authors
Licensed under the MIT License.
https://docs.deno.com/runtime/reference/cli/pack