Publishing a package
Publish to npm, GitHub Packages, GitLab, a private registry, or LPM.dev Registry.
LPM CLI publishes JavaScript packages to npm-compatible registries and LPM.dev Registry. An LPM.dev Registry account is unnecessary for other targets.
From an existing package directory, this sequence publishes to npm:
lpm publish --npm --check
lpm login --npm
lpm publish --npm --dry-run --ignore-scripts
lpm publish --npm --yesThe final command uploads the package and authorizes its publish scripts. If your build is already complete, use --ignore-scripts on that command.
Choose a registry
| Registry | Target flag | Package name and configuration |
|---|---|---|
| npm | --npm | An npm-compatible name, such as @acme/widget. |
| GitHub Packages | --github | A scoped name, such as @acme/widget. |
| GitLab Packages | --gitlab | An npm-compatible name and publish.gitlab.projectId. |
| Private or custom registry | --publish-registry <URL> | An npm-compatible name and the full HTTPS registry endpoint. |
| LPM.dev Registry | --lpm | @lpm.dev/<owner>.<package>, such as @lpm.dev/acme.widget. |
npm-compatible targets default to public access. If the registry must restrict access, set the appropriate access field before publication.
A target flag replaces the target list in lpm.json. Without flags or a configured list, publication targets LPM.dev Registry.
.npmrc install routing does not select the publish target. Use lpm.json or a target flag instead of package.json > publishConfig for registry, access, and tag choices.
Create a package
For a new npm-compatible package, use lpm init:
mkdir widget
cd widget
lpm init --npm --yes --name @acme/widgetThis creates a manifest and selects npm in lpm.json. It does not create source files or build output.
For a new LPM.dev Registry package:
lpm init --lpm --yes --owner acme --name widgetReplace acme with your account or organization slug. Explicit names avoid placeholder values in non-interactive initialization.
For an existing package, keep its manifest. Check the name, version, license, entrypoints, and published files.
package.json > private: true blocks every publication and preview. Private distribution on LPM.dev Registry is a separate access policy.
Save publication defaults
Add this configuration to the package's own lpm.json:
{
"publish": {
"registries": ["npm"],
"npm": {
"name": "@acme/widget",
"access": "public",
"tag": "latest"
}
}
}For a restricted npm package, change access to restricted. npm requires a scoped name for restricted access.
For GitHub, set registries to ["github"] and add github.name and github.access. GitHub otherwise inherits the npm name and access configuration.
For GitLab, include the project ID:
{
"publish": {
"registries": ["gitlab"],
"gitlab": {
"projectId": "12345",
"name": "@acme/widget",
"access": "restricted"
}
}
}For a custom registry, put its full URL in registries. Its package name, access, and tag come from the npm configuration.
Each workspace package needs its own publish configuration. Publication does not inherit these fields from the workspace root.
Authenticate the selected registry
# npm browser login
lpm login --npm
# GitHub or GitLab CLI session, environment token, or stored token
lpm login --github
lpm login --gitlab
# Custom registry: include the endpoint path
lpm login --login-registry https://registry.example.com/npm --token '<token>'
# LPM.dev Registry browser login
lpm loginChoose the command for your target. See authentication for credential sources, storage, and rotation.
Custom registries need credentials for their endpoint. A public npm credential or NPM_TOKEN does not authorize an arbitrary custom registry.
Prepare the files
For editable components or helpers that consumers copy with lpm add, see Source packages.
A typical compiled package includes its output directory:
{
"name": "@acme/widget",
"version": "1.0.0",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",
"files": ["dist"]
}Create the source, README, and license. Run your project's build before a local check:
lpm install
lpm run build
lpm publish --checkUse your existing build script, or configure lpm pack for a library build. Publication creates its archive from the resulting files.
files limits the archive contents. The manifest, README, license files, and required entrypoints can also enter the archive.
Without files, .npmignore takes precedence over .gitignore. Explicitly included files still enter the secret scan, even if Git ignores them.
Publication never packs .lpm/, lpm.lock, or the other committed LPM project files such as lpm-sources.json and lpm-changes/. Credential files such as .env.local and SSH keys stay out of an archive without files. If files selects one, the publish stops. See package contents for the complete lists.
To publish agent skills with an LPM.dev Registry package, put them in lpm-skills/ at the package root. They ship whatever files lists.
If the package declares bundled dependencies, install them before publication. Missing dependencies and unsafe symlinks stop preparation.
Check before uploading
| Command | What happens |
|---|---|
lpm publish --check | Builds the publication archive, lists its files, and checks it locally. No lifecycle scripts, registry requests, or uploads. |
lpm publish --dry-run --ignore-scripts | Checks the selected targets and credentials without lifecycle scripts or uploads. |
lpm publish --dry-run --yes | Runs publish lifecycle scripts and checks the selected targets without uploads. |
Local checks include package configuration, final archive secret scanning, authored skills, supplied provenance files, and applicable quality checks.
Review the listed files before the first upload. JSON output lists them in tarball_files.
Real publication and dry-run can run these scripts in order: prepublishOnly, prepack, prepare, postpack, publish, and postpublish.
These scripts can change local files or contact external services. --yes grants script consent as well as skipping the publication prompt.
For LPM.dev Registry, dry-run can exchange a CI identity for temporary credentials and write authentication audit records. Use --check for checks without that exchange.
Publish once
After the checks pass:
lpm publish --yesThe command uses the configured targets. For one invocation, select a target explicitly:
lpm publish --github --yesFor an LPM.dev Registry quality floor, use these commands instead of the ordinary check and publish:
lpm publish --lpm --check --min-score 80
lpm publish --lpm --yes --min-score 80 --waitThere is no default minimum score. --min-score applies only to that invocation. The Registry calculates its final report after upload.
--wait waits for the uploaded release under its current distribution rules. It does not select a distribution mode.
Publish to multiple registries
Use a name for each registry:
{
"publish": {
"registries": ["npm", "lpm"],
"npm": { "name": "@acme/widget", "access": "public" },
"lpm": { "name": "@lpm.dev/acme.widget" }
}
}Authenticate both targets, then run the check and publication sequence. Each archive receives its target name. The source manifest keeps its original name.
Publish a prerelease
Set publish.npm.tag to next before an npm-compatible prerelease:
lpm version 2.0.0-rc.1 --no-git-tag-version
lpm publish --npm --check
lpm publish --npm --yesOrdinary lpm publish has no --tag flag. Use lpm release publish for publication across selected workspace packages.
Publish from CI
For npm, configure Trusted Publishing for the package, or provide a publish-capable NPM_TOKEN through the CI secret store.
GitHub Actions needs permissions: id-token: write. Other supported CI providers can supply NPM_ID_TOKEN with audience npm:registry.npmjs.org.
LPM CLI attempts the npm identity exchange first. If that exchange fails, it can use an available npm token.
After the build:
lpm publish --npm --check --json
lpm publish --npm --ignore-scripts --yes --jsonFor LPM.dev Registry, configure a trusted publisher for an existing package. GitHub Actions needs permissions: id-token: write.
lpm publish --lpm --check --json
lpm publish --lpm --ignore-scripts --yes --wait --jsonGitLab CI supplies LPM_OIDC_TOKEN with audience https://lpm.dev. A dry-run consumes that supplied assertion, so a later publication needs a fresh assertion.
Add provenance
Replace the final publish command with:
lpm publish --npm --ignore-scripts --yes --provenanceGenerated provenance requires a separate OIDC assertion with the Sigstore audience. GitHub Actions uses id-token: write. GitLab supplies SIGSTORE_ID_TOKEN with audience sigstore.
A provenance identity does not authenticate publication to the registry. npm-compatible provenance also requires public access.
If provenance cannot be generated, publication fails. Use --no-provenance to disable configured provenance for one run.
Choose LPM.dev distribution
New packages start in Private distribution. The dashboard can request Free, Pool, or Marketplace distribution when the account meets the requirements.
Public activation requires review. The package stays private until approval. Activated public modes cannot switch to another mode or return to Private.
See package distribution for access, eligibility, dependency restrictions, and review states.
Recover from a failed publication
- Invalid name or target: Check the resolved names and registry configuration before another upload.
- Secret scan failure: Remove the secret from the published files and rotate an exposed credential.
- Version already exists: Inspect that version before choosing a new version with lpm version.
- One target failed: Retry only that target. Successful uploads do not roll back across registries.
- A post-publish script or publication wait failed: The upload can already exist. Inspect the registry before retrying.
- Trusted Publisher exchange failed: Check the package's trust configuration, workflow identity, and token audience.
See also
- Source packages — prepare editable source for consumers
- lpm publish — complete options and target behavior
- lpm init — package initialization
- lpm release — workspace publication
- lpm quality — completed quality reports
- CI/CD setup — reproducible installs and credentials
- Using with Swift — Swift publication