Skip to main content
Publish a package to the npm registry.
bun publish

Behavior

bun publish packages your project into a tarball and publishes it to the npm registry (or a private registry). It:
  1. Validates package.json (checks for required fields)
  2. Runs lifecycle scripts (prepare, prepublish, prepublishOnly)
  3. Creates a tarball of your package
  4. Uploads the tarball to the registry
  5. Runs postpublish scripts

Prerequisites

Authentication

You must be logged in to npm:
bunx npm login
This stores credentials for publishing.

Required package.json fields

Your package.json must have:
{
  "name": "my-package",
  "version": "1.0.0"
}

Publishing modes

Publish from directory (default)

bun publish
Automatically packs and publishes the current directory.

Publish a tarball

bun publish ./my-package-1.0.0.tgz
Publish a pre-built tarball.

Flags

--tag <tag>

Publish with a specific dist-tag (default: latest).
bun publish --tag beta
Common tags:
  • latest (default) - Stable release
  • next - Pre-release / canary
  • beta - Beta version
  • alpha - Alpha version
  • rc - Release candidate
Users can install tagged versions:
bun add my-package@beta

--access <public|restricted>

Set package access level.
# Publish as public (required for unscoped packages)
bun publish --access public

# Publish as restricted (only for scoped packages)
bun publish --access restricted
Note: Unscoped packages must be public. Scoped packages (@org/package) can be public or restricted.

--dry-run

Simulate publishing without actually uploading to the registry.
bun publish --dry-run
Shows what would be published:
packed 15 files (42.3 KB)
unpacked size: 128 KB
tarball: my-package-1.0.0.tgz
shasum: a1b2c3d4e5...
integrity: sha512-AbCd...

Tag: latest
Access: public
Registry: https://registry.npmjs.org/

[dry-run] Would publish

--otp <code>

Provide a one-time password for two-factor authentication.
bun publish --otp 123456
If you have 2FA enabled and don’t provide --otp, Bun will prompt for it.

--no-ignore-scripts

Run lifecycle scripts (enabled by default). Use to explicitly enable scripts.
bun publish --no-ignore-scripts

--ignore-scripts

Skip running lifecycle scripts.
bun publish --ignore-scripts

--cwd <path>

Run command in specified directory.
bun publish --cwd ./packages/my-package

Lifecycle scripts

Bun runs these scripts in order:
  1. prepare - Before packing, after npm install
  2. prepublishOnly - Before packing, only on bun publish
  3. prepack - Before tarball is created
  4. postpack - After tarball is created
  5. publish - After publishing (on success)
  6. postpublish - After publishing (on success)
Example in package.json:
{
  "scripts": {
    "prepare": "bun run build",
    "prepublishOnly": "bun test",
    "postpublish": "echo 'Published!'"
  }
}

Files included

By default, these files are included:
  • All files in the project
  • Respects .npmignore or files field in package.json

Using files field

{
  "files": [
    "dist",
    "README.md",
    "LICENSE"
  ]
}
Only specified files/directories are included.

Always included

  • package.json
  • README / README.md
  • LICENSE / LICENCE
  • CHANGELOG / CHANGELOG.md

Always excluded

  • .git
  • node_modules
  • .env files
  • .DS_Store

publishConfig

Configure publishing behavior in package.json:
{
  "publishConfig": {
    "access": "public",
    "tag": "latest",
    "registry": "https://registry.npmjs.org/"
  }
}

Examples

Basic publish

$ bun publish
bun publish v1.0.0

packed 15 files
unpacked size: 128 KB
packed size: 42.3 KB
shasum: a1b2c3d4e5f6...
integrity: sha512-AbCdEf...

Tag: latest
Access: public  
Registry: https://registry.npmjs.org/

+ [email protected]

Publish beta version

$ bun publish --tag beta
bun publish v1.0.0

+ [email protected] (beta)

Publish with dry run

$ bun publish --dry-run
bun publish v1.0.0

packed 15 files (42.3 KB)

Tag: latest
Access: public
Registry: https://registry.npmjs.org/

+ [email protected] (dry-run)

Publish with 2FA

$ bun publish
bun publish v1.0.0

This operation requires a one-time password.
Enter OTP: 123456

+ [email protected]
Or provide OTP directly:
bun publish --otp 123456

Publishing workflow

Typical workflow for publishing a new version:
# 1. Update version
bun pm version patch

# 2. Test before publishing
bun test

# 3. Dry run to verify package contents
bun publish --dry-run

# 4. Publish
bun publish

# 5. Tag git release (optional)
git push --follow-tags

Private packages

Publish to a private registry:
{
  "publishConfig": {
    "registry": "https://npm.pkg.github.com/",
    "access": "restricted"
  }
}

Scoped packages

Publish scoped packages:
{
  "name": "@myorg/my-package",
  "publishConfig": {
    "access": "public"
  }
}
bun publish --access public

Prevent accidental publishing

Mark a package as private to prevent publishing:
{
  "private": true
}
Attempting to publish will fail:
$ bun publish
error: attempted to publish a private package

Verify published package

After publishing, verify:
# View on registry
bun pm view my-package

# Install and test
cd /tmp
bun add my-package

Unpublishing

To unpublish a version:
npx npm unpublish [email protected]
Note: You can only unpublish within 72 hours. After that, contact npm support.

Common errors

Missing authentication

error: missing authentication (run `bunx npm login`)
Run bunx npm login first.

Package already exists

error: cannot publish over existing version
Increment version with bun pm version patch.

Private package

error: attempted to publish a private package
Remove "private": true from package.json.

Unscoped package requires public access

error: unable to restrict access to unscoped package
Use --access public or scope the package.

Build docs developers (and LLMs) love