Skip to main content
Where Deploy an API ships a container, publishing to npm ships libraries: the packages under packages/ and the modules under modules/ that other projects install. Talos drives the whole flow from the CLI — save a token once, then let npm:publish pack each target, resolve its workspace dependencies to real version ranges, and push it to the registry. Versions already on npm are skipped, so re-running never double-publishes. The guiding principle is version in git, publish from git. release:create bumps versions, writes changelogs, and tags from your conventional commits; npm:publish takes those tagged versions to the registry. The two compose into a single command when you pass --publish.

What gets published

Every directory under packages/ and modules/ is a candidate. Each must carry a package.json whose name and version define the published artifact.
SourceLocationTypical use
Packagespackages/<name>/Framework-agnostic libraries (@talosjs/logger, @talosjs/command, …).
Modulesmodules/<name>/Business-domain modules published for reuse across services.
npm:publish publishes the package’s dist/ as-is. Build your artifacts (so dist/ is current) before publishing — the command packs what is on disk; it does not run your build.

Step 1 — Save an npm token

Publishing authenticates with an npm Granular Access Token. Save it once with npm:credentials:create; it is written as block-style YAML to ~/.talos/credentials/npm.yml under the default profile and reused by every publish.
talos npm:credentials:create
You are prompted for the token (input hidden), or pass it non-interactively for CI:
talos npm:credentials:create --token=npm_xxxxxxxxxxxxxxxx --silent
Create the token at npmjs.com → Granular Access Tokens. Scope it with read and write access to exactly the packages (or scope) you publish, and give it the shortest expiry your release cadence allows.
The token is stored in plaintext under ~/.talos/credentials/. Keep that directory off shared machines and out of any backup that leaves your control. In CI, inject the token via --token from a secret store rather than committing npm.yml.

Step 2 — Publish

With a token saved, publish everything in the workspace:
talos npm:publish
Or target specific packages and modules by name (comma-separated):
talos npm:publish --packages=cli,logger
talos npm:publish --modules=billing,catalog
For a scoped package that should be private, publish with restricted access:
talos npm:publish --packages=cli --access=restricted

Options

OptionDescriptionDefault
--packagesComma-separated package names to publish (under packages/).All packages and modules
--modulesComma-separated module names to publish (under modules/).All packages and modules
--accessnpm access level: public or restricted.public
--silentSuppress log output and the publishing spinner (use in CI).false

What the command does per target

For each resolved target, npm:publish:
  1. Checks the registry for the target’s name@version. If that version already exists, it is reported as ignored and skipped — this is what makes re-runs safe.
  2. Packs with bun pm pack into dist/, so workspace:* dependencies resolve to real published version ranges instead of workspace protocols.
  3. Extracts the tarball into dist/publish, stripping npm’s package/ prefix so the resolved package.json lands at the root.
  4. Publishes with npm publish --access <access> from dist/publish, authenticating with your saved token. (npm, not bun publish, is used deliberately — it avoids the interactive web-OTP flow.)
  5. Cleans up the tarball and dist/publish afterward, so nothing leaks into the next packed artifact.
At the end it prints a summary — N published, M ignored.
Because publishing packs with bun but publishes with npm, both must be on PATH. A version whose name@version is already on the registry is never re-published, so bumping the version (Step 3) is what makes a new publish happen.

Step 3 — Version and publish together

You rarely publish a hand-edited version. Instead let release:create derive the next version from your conventional commits — a breaking change bumps major, a feat bumps minor, anything else patches — then write the changelog, commit, and tag. Passing --publish hands the freshly released targets straight to npm:publish:
talos release:create --publish
This single command:
  1. Verifies the working tree is clean (aborts otherwise).
  2. For each package/module with unreleased commits, bumps its version, updates CHANGELOG.md, commits, and creates an annotated git tag.
  3. Prompts to push commits and tags to the remote (also refreshes and commits bun.lock).
  4. Publishes only the targets it released this run to npm.
Scope a release to specific targets the same way, and still publish:
talos release:create --packages=cli,logger --publish
Keep release:create as the front door for versioning and reach for bare npm:publish only to retry a publish that failed after the version was already tagged — the registry check means the already-published siblings are simply skipped.

Publish from CI

The same two commands run unattended. Provide the token from a secret and add --silent to keep logs clean:
.github/workflows/publish.yml
name: publish
on:
  push:
    tags: ["*@*"]        # matches release:create tags, e.g. @talosjs/cli@1.2.0
jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: oven-sh/setup-bun@v2
      - run: bun install
      - run: bun run build
      - run: bunx talos npm:credentials:create --token="$NPM_TOKEN" --silent
        env:
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
      - run: bunx talos npm:publish --silent
Give the CI token write access only to the packages you publish, and prefer a short expiry. Because the registry check skips already-published versions, a re-triggered pipeline is idempotent — but a leaked long-lived token is not.

Checklist

  • Save the npm token once with npm:credentials:create (or inject it via --token in CI).
  • Build so each target’s dist/ is current before publishing.
  • Let release:create derive versions from conventional commits — don’t hand-edit them.
  • Use release:create --publish for the normal flow; reserve bare npm:publish for retries.
  • Pass --access=restricted for private scoped packages.
  • In CI, add --silent and pull the token from a secret store — never commit npm.yml.