# Heroku Buildpack for Node.js: Lockfiles and Runtime Selection

> Heroku's official classic buildpack turns a Node.js application's package metadata into a Heroku build and selects npm, Yarn, or pnpm from its lockfile. It suits applications that want platform-managed runtime selection with explicit control over the Node.js major version.

**heroku/heroku-buildpack-nodejs** — Heroku's classic buildpack for Node.js apps

- Repository: https://github.com/heroku/heroku-buildpack-nodejs
- Website: https://devcenter.heroku.com/categories/nodejs-support
- Stars: 1,348 · Forks: 2,610
- Language: Shell
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/heroku-heroku-buildpack-nodejs

## What Heroku's Node.js Buildpack Solves

This repository contains Heroku's classic buildpack for Node.js applications. Its scope is the deployment path inside Heroku, not application development on a developer laptop. The buildpack reads the application source and prepares it for a Node.js build while applying Heroku's runtime rules.

The immediate contract is narrow: `package.json` must exist in the application's root directory. From there, the buildpack identifies the package manager through the lockfile. This makes the repository relevant to teams that already have a Heroku-hosted Node.js app and want their dependency manager and runtime declaration to influence the build. It is less relevant to someone looking for a local development installer, because the README does not provide a local installation command.

The project also makes a clear reproducibility choice. A lockfile is not mandatory, but the README strongly recommends one. Without a lockfile, the buildpack falls back to npm. That fallback keeps a minimal application buildable, yet it removes the lockfile-based selection mechanism that many production applications rely on.

## How Lockfiles Select npm, Yarn, or pnpm

The package-manager decision is driven by files in the application's top-level directory rather than by a separate buildpack setting. The documented mapping is direct: `package-lock.json` selects npm, `yarn.lock` selects Yarn, and `pnpm-lock.yaml` selects pnpm. If none is present, npm is used.

This mechanism gives existing Node.js teams three workable paths. A team can keep npm and commit `package-lock.json`, use Yarn with `yarn.lock`, or use pnpm with `pnpm-lock.yaml`. The buildpack does not need the application to encode the package-manager choice in a custom configuration key for this purpose. Instead, the dependency-resolution artifact already used by the project also communicates which workflow the project expects.

That approach has a practical consequence. Adding, retaining, or changing a lockfile is part of runtime and build configuration. A repository that uses a different dependency tool but commits none of the three recognized lockfiles will fall into the npm default. The README recommends lockfiles for reproducible builds, so the default should be treated as a fallback rather than a substitute for an explicit dependency-management choice.

## Setting engines.node for Heroku's Runtime

The runtime version comes from the `engines.node` field in `package.json`. The README recommends a major version range such as `24.x` rather than an exact version. Its stated reason is that a major range allows the application to receive Node.js security and bug-fix updates.

This is a real operational boundary. The buildpack does not simply read whatever Node.js executable happens to be present in the source tree, based on the documentation. It uses `engines.node`, or its documented default when the field is absent. If the application does not specify a version, the buildpack uses the current recommended LTS release.

Exact versions offer a different tradeoff from major ranges. The README does not document rollback behavior, version retention periods, or every way a prior runtime can be restored, so those details should not be inferred. Before choosing a narrower declaration, check the linked Heroku Node.js Support documentation for the available versions.

## Preparing a First Heroku Node.js Application

The repository's Getting Started section sends readers to the external "Getting Started with Node.js on Heroku" tutorial. It does not document a `git clone` command, Heroku CLI invocation, dependency installation command, or local setup command for this buildpack. For that reason, this tutorial includes only the project configuration stated in the repository and does not invent deployment commands.

Start with a Node.js application whose `package.json` is at the top level of the source code. If the app is intended to run Node.js 24, the README gives this exact configuration:

```json
{
  "engines": {
    "node": "24.x"
  }
}
```

This declaration tells the buildpack which Node.js major line to select. The reader should expect the setting to live in the application's existing `package.json`, not in a file invented specifically for the buildpack. If `engines.node` is absent, the documented behavior is selection of the current recommended LTS release.

Next, ensure the source root contains the lockfile associated with the dependency workflow. The README does not provide commands for generating those files, so lockfile creation is outside the documented scope of this tutorial. Follow the package manager used by the application and commit the resulting recognized lockfile. A production application should avoid relying on the no-lockfile npm fallback merely because the initial `package.json` happens to build.

## npm, Yarn, and pnpm as Different Build Inputs

npm, Yarn, and pnpm are the documented alternatives within this buildpack, and their difference is determined by which lockfile the application includes. npm is selected by `package-lock.json`, Yarn by `yarn.lock`, and pnpm by `pnpm-lock.yaml`. npm also becomes the fallback when none of these files is present.

The practical alternative to changing the buildpack is therefore changing the application's dependency-management contract. A project standardized on Yarn should not rely on npm merely because its lockfile was omitted. A pnpm project can keep `pnpm-lock.yaml` so the buildpack follows the package manager associated with that project.

The README does not document flags for forcing a package manager when the chosen lockfile disagrees with local developer tooling. It also does not describe package installation commands. This means the lockfile mapping is clear, while troubleshooting lockfile inconsistency is not. Engineers need the lockfile, application metadata, and Heroku build logs to agree before expecting the build to reflect a particular dependency workflow.

## Limits of the Classic Node.js Buildpack

The clearest limitation is platform scope. This is the classic buildpack for Node.js apps on Heroku, and its documentation points readers to Heroku Dev Center for Node.js support. It is not documented as a local runtime manager, a generic deployment script, or a portable image specification for non-Heroku environments.

A second limitation is the ambiguity created when no lockfile exists. The build can use npm, but the README's recommendation for reproducible builds points in another direction. This fallback avoids a hard requirement for lockfiles, yet it does not tell the reader which package-manager intent the source project had. The absence of `package-lock.json`, `yarn.lock`, and `pnpm-lock.yaml` should therefore be reviewed before a production build.

The documentation is also deliberately limited around upgrades. It gives the supported version source, version-selection examples, and release metadata in the repository, but the cleaned README does not document dependency caching controls, build failure diagnostics, runtime rollback commands, or manual override behavior. Those topics should not be assumed merely because they are common concerns in deployment systems.

## Maintenance, Releases, and the MIT License

The repository is not archived. Its last push was on 2026-10-15, and the recent release history includes v373 on 2026-10-08, v372 on 2026-10-06, and v371 on 2026-10-02. These dates show recent repository and release activity, but they do not by themselves establish compatibility with every Node.js application.

The project is primarily written in Shell and is distributed under the MIT License. The repository includes `LICENSE`, `CHANGELOG.md`, `SECURITY.md`, `CONTRIBUTING.md`, test directories, and support directories. The README itself directs users to Heroku Dev Center for operational documentation rather than reproducing the full support matrix here.

For an adopting team, upgrade cost depends on matching the application's Node.js major version, package manager, and lockfile to what the buildpack supports. The documentation specifically warns against exact runtime pinning when major ranges are sufficient, because exact pins reduce automatic receipt of security and bug-fix updates. The first verification should therefore be the current Heroku Node.js Support list, followed by confirmation that the application's `engines.node` and lockfile describe the same build it expects.

## Conclusion

Adopt this buildpack when deploying a Node.js application to Heroku and you want package-manager selection based on a committed lockfile plus control through `engines.node`. Do not treat it as a general-purpose installer or a Node.js container definition. Before adoption, verify that `package.json` is at the source root, choose the lockfile that matches the application's actual workflow, and confirm that the requested Node.js major version remains in Heroku's supported list.

## FAQ

### Which package manager does Heroku Buildpack for Node.js use?

It selects npm for `package-lock.json`, Yarn for `yarn.lock`, and pnpm for `pnpm-lock.yaml`. If no supported lockfile is found, it uses npm.

### How do I choose the Node.js version in Heroku Buildpack for Node.js?

Set `engines.node` in the root-level `package.json`. The README recommends a major range such as `24.x`; without that field, the buildpack uses the current recommended LTS release.

### Does Heroku Buildpack for Node.js require a lockfile?

No. The buildpack falls back to npm when none of the recognized lockfiles is present, but the README strongly recommends a lockfile for reproducible builds.

## Sources

- [heroku/heroku-buildpack-nodejs on GitHub](https://github.com/heroku/heroku-buildpack-nodejs)
- [License: MIT](https://github.com/heroku/heroku-buildpack-nodejs/blob/main/LICENSE)
- [Project website](https://devcenter.heroku.com/categories/nodejs-support)
- [README](https://github.com/heroku/heroku-buildpack-nodejs/blob/main/README.md)
- [Releases](https://github.com/heroku/heroku-buildpack-nodejs/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/heroku-heroku-buildpack-nodejs
