diff --git a/.gitignore b/.gitignore
index f727868e..788739fd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,6 @@
.idea
dist/
node_modules/
-package-lock.json
.tool-versions
packaged/
diff --git a/Cargo.lock b/Cargo.lock
index e1832b6c..b47e9847 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -642,6 +642,8 @@ version = "0.0.0"
dependencies = [
"anyhow",
"chrono",
+ "commons",
+ "indoc",
"node-semver",
"opentelemetry",
"opentelemetry-stdout",
@@ -690,6 +692,23 @@ dependencies = [
"toml 0.8.2",
]
+[[package]]
+name = "heroku-npm-install-buildpack"
+version = "0.0.0"
+dependencies = [
+ "commons",
+ "heroku-nodejs-utils",
+ "indoc",
+ "libcnb 0.15.0",
+ "libcnb-test",
+ "libherokubuildpack 0.15.0",
+ "serde",
+ "serde_json",
+ "test_support",
+ "toml 0.8.2",
+ "ureq",
+]
+
[[package]]
name = "hex"
version = "0.4.3"
diff --git a/Cargo.toml b/Cargo.toml
index 01a940d8..9df85826 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,6 +4,7 @@ members = [
"buildpacks/nodejs-corepack",
"buildpacks/nodejs-function-invoker",
"buildpacks/nodejs-npm-engine",
+ "buildpacks/nodejs-npm-install",
"buildpacks/nodejs-pnpm-install",
"buildpacks/nodejs-yarn",
"common/nodejs-utils",
diff --git a/README.md b/README.md
index 9072218a..05f19d91 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,7 @@ Heroku's official [Cloud Native Buildpacks](https://buildpacks.io) for the Node.
| `heroku/nodejs-corepack` | Corepack | [Readme](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/nodejs-corepack/README.md) | [Changelog](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/nodejs-corepack/CHANGELOG.md) | [](https://registry.buildpacks.io/buildpacks/heroku/nodejs-corepack) |
| `heroku/nodejs-npm` | npm | [Readme](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/npm/README.md) | [Changelog](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/npm/CHANGELOG.md) | [](https://registry.buildpacks.io/buildpacks/heroku/nodejs-npm) |
| `heroku/nodejs-npm-engine` | npm Engine | [Readme](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/nodejs-npm-engine/README.md) | [Changelog](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/nodejs-npm-engine/CHANGELOG.md) | [](https://registry.buildpacks.io/buildpacks/heroku/nodejs-npm-engine) |
+| `heroku/nodejs-npm-install` | npm Install | [Readme](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/nodejs-npm-install/README.md) | [Changelog](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/nodejs-npm-install/CHANGELOG.md) | [](https://registry.buildpacks.io/buildpacks/heroku/nodejs-npm-install) |
| `heroku/nodejs-pnpm-install` | pnpm install | [Readme](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/nodejs-pnpm-install/README.md) | [Changelog](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/nodejs-pnpm-install/CHANGELOG.md) | [](https://registry.buildpacks.io/buildpacks/heroku/nodejs-pnpm-install) |
| `heroku/nodejs-yarn` | Yarn | [Readme](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/nodejs-yarn/README.md) | [Changelog](https://github.com/heroku/buildpacks-nodejs/blob/main/buildpacks/yarn/CHANGELOG.md) | [](https://registry.buildpacks.io/buildpacks/heroku/nodejs-yarn) |
diff --git a/buildpacks/nodejs-engine/tests/integration_test.rs b/buildpacks/nodejs-engine/tests/integration_test.rs
index f962dd24..79537df1 100644
--- a/buildpacks/nodejs-engine/tests/integration_test.rs
+++ b/buildpacks/nodejs-engine/tests/integration_test.rs
@@ -1,6 +1,6 @@
#![warn(clippy::pedantic)]
-use libcnb_test::{assert_contains, assert_not_contains};
+use libcnb_test::assert_contains;
use test_support::{
assert_web_response, nodejs_integration_test, nodejs_integration_test_with_config,
set_node_engine,
@@ -47,37 +47,3 @@ fn reinstalls_node_if_version_changes() {
},
);
}
-
-// TODO: move this test & fixture to the npm buildpack once that is ready
-#[test]
-#[ignore]
-fn npm_project_with_no_lockfile() {
- nodejs_integration_test("../../../test/fixtures/npm-project", |ctx| {
- assert_contains!(ctx.pack_stdout, "Installing Node");
- assert_contains!(ctx.pack_stdout, "Installing node modules");
-
- assert_not_contains!(ctx.pack_stdout, "Installing yarn");
- assert_not_contains!(ctx.pack_stdout, "Installing node modules from ./yarn.lock");
- assert_not_contains!(
- ctx.pack_stdout,
- "Installing node modules from ./package-lock.json"
- );
- });
-}
-
-// TODO: move this test & fixture to the npm buildpack once that is ready
-#[test]
-#[ignore]
-fn npm_project_with_lockfile() {
- nodejs_integration_test("../../../test/fixtures/npm-project-with-lockfile", |ctx| {
- assert_contains!(ctx.pack_stdout, "Installing Node");
- assert_contains!(ctx.pack_stdout, "Installing node modules");
- assert_contains!(
- ctx.pack_stdout,
- "Installing node modules from ./package-lock.json"
- );
-
- assert_not_contains!(ctx.pack_stdout, "Installing yarn");
- assert_not_contains!(ctx.pack_stdout, "Installing node modules from ./yarn.lock");
- });
-}
diff --git a/buildpacks/nodejs-npm-install/CHANGELOG.md b/buildpacks/nodejs-npm-install/CHANGELOG.md
new file mode 100644
index 00000000..8253ed02
--- /dev/null
+++ b/buildpacks/nodejs-npm-install/CHANGELOG.md
@@ -0,0 +1,13 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [Unreleased]
+
+### Added
+
+- Initial release
+
\ No newline at end of file
diff --git a/buildpacks/nodejs-npm-install/Cargo.toml b/buildpacks/nodejs-npm-install/Cargo.toml
new file mode 100644
index 00000000..a1aac45b
--- /dev/null
+++ b/buildpacks/nodejs-npm-install/Cargo.toml
@@ -0,0 +1,22 @@
+[package]
+name = "heroku-npm-install-buildpack"
+description = "Heroku Node.js npm Install Cloud Native Buildpack"
+version.workspace = true
+rust-version.workspace = true
+edition.workspace = true
+publish.workspace = true
+
+[dependencies]
+commons.workspace = true
+heroku-nodejs-utils.workspace = true
+libcnb.workspace = true
+libherokubuildpack.workspace = true
+serde.workspace = true
+indoc.workspace = true
+toml.workspace = true
+
+[dev-dependencies]
+libcnb-test.workspace = true
+serde_json.workspace = true
+test_support.workspace = true
+ureq.workspace = true
diff --git a/buildpacks/nodejs-npm-install/README.md b/buildpacks/nodejs-npm-install/README.md
new file mode 100644
index 00000000..87a1895b
--- /dev/null
+++ b/buildpacks/nodejs-npm-install/README.md
@@ -0,0 +1,65 @@
+# Heroku Cloud Native npm Install Buildpack
+
+[![CI][CI BADGE]][CI LINK] [![Registry][Registry BADGE]][Registry LINK]
+
+Heroku's official Cloud Native Buildpack for executing `npm install`.
+
+## How it works
+
+The buildpack will pass detection if:
+
+- A `package-lock.json` file is found at the root of the application source.
+
+### Step 1: Configure npm cache
+
+Node modules downloaded during the [install step](#step-2-install-node-modules) will be cached. Subsequent builds will use
+this cache speed up installs.
+
+### Step 2: Install Node modules
+
+Node modules are installed by executing `npm ci --production=false`.
+
+### Step 3: Execute build scripts
+
+The following scripts will be executed with `npm run