Publishing
Early access
The CLI generator is in early access. Reach out to get started.
Publish your generated CLI to npm. After following the steps on this page, each tagged release builds cross-platform binaries, attaches them to a GitHub Release, and publishes them to npm automatically. Homebrew and Scoop are opt-in channels on top of the same release. To keep generation on your own infrastructure, you can self-host the generator instead of using Fern’s cloud.
This page assumes that you have:
- An initialized
fernfolder withgenerators.ymlconfigured for the CLI generator. See Quickstart. - An existing GitHub repository for the generated CLI source, with the Fern GitHub App installed on it.
Configure output location
Set the output location to npm
In the group for your CLI, set the output location to npm:
Add a unique package name
The package name must be unique in the npm registry.
The npm package name is independent of the generated Rust crate’s identity. To publish the crate under your own name, license, repository, and authors, set packageIdentity in the generator’s config.
Configure GitHub publishing
Fern publishes your CLI via GitHub Actions. Configure your GitHub repository and publishing mode:
The repository owner is independent of your Fern organization (the --organization value passed to fern init). Point it at the GitHub user or organization that owns the target repository.
Configure authentication
Choose how to authenticate with npm when publishing.
OIDC authentication (Recommended)
OIDC-based publishing (trusted publishing) is the most secure option. npm trusts your GitHub repository to publish directly — no tokens to manage.
Create the packages on npm
The CI workflow publishes one launcher package and one package per platform. For a package named @myorg/my-cli, that’s:
OIDC can’t perform a package’s first publish; npm requires a package to exist before you can add a trusted publisher. Run the following script to create and publish a placeholder for each package:
Authorize your repository on npmjs.com
Configure trusted publishing on npmjs.com. Repeat this for every package listed above — an OIDC run fails on any package that has no trusted publisher.
- Open the package page on npmjs.com and go to the Settings tab
- Find the Trusted Publisher section and click Add trusted publisher
- Select GitHub Actions as your provider
- Fill in:
- Organization or user: Your GitHub username or organization
- Repository: Your CLI repository name (e.g.
my-cli) - Workflow filename:
ci.yml - Environment name: Leave blank
- Under Allowed actions, select Allow
npm publish
Token-based authentication
Generate an npm token
- Log into npmjs.com
- Click your profile picture and select Access Tokens
- Click Generate New Token and create a granular access token
- Give it Read and Write access to All packages
- Save your token securely
Configure distribution channels
Homebrew and Scoop are optional channels that install from the archives attached to each GitHub Release, so both require GitHub publishing. Add the channels you want under distribution in the generator’s config:
On the next generation, Fern adds a publish-homebrew-formula job, a publish-scoop job, or both to the release workflow, along with the matching install commands in the generated README. Prereleases are skipped: a tap and a bucket have no prerelease channel, so an RC never becomes the version users install.
Each channel needs a repository and credentials before that first release:
Create the tap and bucket repositories
Create a public GitHub repository for each channel you enable — conventionally homebrew-tap and scoop-bucket. They can be empty; the release workflow commits the formula and the manifest into them. A private tap or bucket breaks installation for users who lack access to it.
Add credentials with write access to them
The workflow’s built-in GITHUB_TOKEN is scoped to the CLI repository and can’t push to another one, so each channel authenticates with credentials you store as Actions secrets in the CLI repository, under Settings > Secrets and variables > Actions. A personal access token is the quickest to set up; a GitHub App keeps release access off any individual’s account.
Personal access token
GitHub App
One token per channel, each with write access to that channel’s repository:
A token belongs to a person and doesn’t expire, so releases break once that person’s access ends.
Publish your CLI
How you trigger a publish depends on your mode:
- In
releasemode,fern generate --group clicommits the updated source and tags a release. The tag triggers the CI workflow (no manual release step). - In
pull-requestmode,fern generate --group cliopens a PR. Merge it, then create a GitHub release with a version tag (e.g.v1.0.0) to trigger publishing.
The CI workflow then builds binaries for all platforms, attaches the archives and the curl | bash and PowerShell installers to the GitHub Release, publishes to npm, and updates any configured tap or bucket.
Build targets
The CI workflow produces statically linked binaries for:
The npm package wraps the native binary with a Node.js launcher. Platform-specific optional dependencies ensure only the correct binary downloads at install time.
Install instructions for users
After publishing, direct users to whichever channel they prefer. Every generated CLI supports npm and the installers attached to the GitHub Release:
With distribution.homebrew configured, a tap named my-org/homebrew-tap resolves as my-org/tap:
With distribution.scoop configured, users add the bucket once, then install:
Scoop covers x86_64 Windows only; ARM64 Windows users install through npm or the PowerShell installer. self-update replaces the binary in place rather than deferring to brew upgrade or scoop update, so those package managers can report an older version than the one installed.