Docs menu

Package managers

How Bun installs dependencies on Primcloud: lockfile requirements, frozen installs, private registries, and Bun as the asset builder for Ruby, PHP, and Rust apps.

On this page

Bun is its own package manager. A Bun app on Primcloud installs with bun install; npm, pnpm, and Yarn aren't involved. This page covers what the install runs, what it needs from your lockfile, how to point it at a private registry, and how Bun builds frontend assets for apps written in other languages.

Supported package manager#

Bun. The same Bun binary that runs your app installs its dependencies, at the version resolved on the Runtime versions page. Both lockfile formats are recognized: the text bun.lock and the older binary bun.lockb.

An app that uses npm, pnpm, or Yarn (a package.json with no Bun lockfile and no other Bun marker) is a Node.js app. See Node.js package managers.

Install behavior#

With a lockfile. The build runs bun install --frozen-lockfile. Bun installs exactly what the lockfile records and fails if the lockfile doesn't match package.json, with no version resolution at deploy time.

Without a lockfile. The build runs a plain bun install and expects it to have nothing to do. That's the case for an app with no dependencies, which Bun writes no lockfile for. If the install does write a lockfile, the app has dependencies it never locked, and the build fails with a "Missing Bun lockfile" error.

Dev dependencies are installed, so they're available to your build scripts.

After install: the build runs your build scripts and then removes packages your lockfile doesn't list with bun prune (on Bun 1.4.0 and newer). Dev dependencies stay installed.

Bun's download cache is kept between builds, so unchanged dependencies aren't fetched again.

Private packages and registries#

Pointing the install at a private registry uses Bun's standard configuration. Primcloud doesn't add a mechanism of its own. Declare the scope in bunfig.toml and reference the token through an environment variable so the token itself never enters the repo:

bunfig.toml
[install.scopes]
"@my-org" = { token = "$MY_ORG_NPM_TOKEN", url = "https://npm.pkg.example.com/" }

Then set MY_ORG_NPM_TOKEN in the Secrets panel on the dashboard. Secrets are visible to bun install during the build.

Bun also reads .npmrc, so a registry already configured there for npm keeps working. See Bun's scopes and registries reference for every option.

Warning

Never commit tokens. Set them in the Secrets panel. Like every secret, they're stored encrypted and never surfaced in build logs.

Lockfiles#

App has Lockfile
Dependencies Required. Commit bun.lock (or bun.lockb).
No dependencies Not needed. Mark the repo as a Bun app with bunfig.toml, .bun-version, or a packageManager field instead.

Regenerate the lockfile with bun install whenever package.json changes, and commit it.

Lockfile drift. If package.json and the lockfile disagree, install fails. Reproduce locally with bun install --frozen-lockfile, the same command the build runs.

One lockfile. Delete lockfiles from other package managers. A stray package-lock.json or yarn.lock beside bun.lock is a source of confusion about which tool owns the dependency tree.

Bun as the asset builder for other languages#

Bun doesn't have to be the app. A Ruby, PHP, or Rust app that keeps a package.json for its frontend gets that frontend built with Bun when the repo is marked as a Bun project, which in practice means when bun.lock is committed beside package.json.

App Detected by What Bun does web process
Ruby Gemfile.lock Installs Bun and your JavaScript dependencies, runs your build scripts. bun is on PATH when rake assets:precompile runs. Your Procfile, or the web process detected from your gems.
PHP composer.json Runs after composer install, so vendor/ is in place. Installs Bun and your JavaScript dependencies, runs your build scripts. Your Procfile. Without one, see below.
Rust Cargo.toml Runs before cargo build. Installs Bun and your JavaScript dependencies, runs your build scripts. Your Procfile. Without one, your Rust binary.

In all three:

  • The install, build scripts, and pruning are the same as for a Bun app, described above.
  • A web line in your Procfile always decides the web process.
  • With a Procfile that has no web line, a PHP or Rust app that has a root server.js, index.js, server.ts, or index.ts starts that file with Bun as web. Declare web in the Procfile.
  • Without a Procfile, a Rails, Rack, or Rust app still starts its own web process, whatever package.json says.
  • Without a Procfile, a PHP app, or a Ruby app with no detected web process, starts with Bun when the repo gives it a way to: a start script in package.json, or a root server.js, index.js, server.ts, or index.ts. Add a Procfile with a web line to keep your own server in charge.
  • In a PHP or Rust app, Bun is the only JavaScript runtime installed. A build tool that starts itself with node, such as Vite, runs on Bun. A Ruby app gets Node.js as well.
  • The Bun version is pinned the same way; see Runtime versions.

Each language documents this from its own side: Ruby on Primcloud → Detection, PHP → Customizing the build, and Rust on Primcloud → Frontend assets.