# ADR-0015: Node install logic paired across buildNode.groovy and Dockerfile **Status:** Accepted **Category:** PATTERN **Date decided:** Early on **Date documented:** 2026-05-13 ## Context Meesho Node services use both `npm` and `pnpm` depending on the repo. Some teams need to pass extra flags (e.g. `--legacy-peer-deps`) and the shared library cannot anticipate every combination. The install step has to run inside the Docker build (the image needs `node_modules` baked in), but the choice of *which* package manager and *which* flags to run is information the Dockerfile alone can't recover from a clean container — it has to be told. ## Decision The install step is split deliberately across the two files. `src/com/meesho/stages/buildNode.groovy` does the detection: it reads `config.yaml`, sees whether the repo uses `npm` or `pnpm`, and resolves the optional `npm_install_arg` override; it then passes the resolved values to `resources/com/meesho/node-Dockerfile` as Docker build-args. The Dockerfile does the execution: it consumes those build-args and runs the actual install, falling back to a sane default in an `else` branch when no value was passed. Detection lives at the layer that can see the config; execution lives at the layer that runs inside the container. ## Alternatives Considered No alternatives were explicitly evaluated by the team during this interview. The split mirrors what is naturally separable — config interpretation vs runtime install — and has not been revisited. ## Consequences **Positive:** - Teams can override the install command for their service through `npm_install_arg` in `config.yaml` without forking the library Dockerfile — observed in #devops-tech (Nov 2025) when a team added `--legacy-peer-deps` purely via config. - The Dockerfile's `else` fallback means a developer can `docker build` locally without Jenkins or `config.yaml` and still get a working install. - Neither layer needs to know more than it actually does: Groovy doesn't run `npm`, the Dockerfile doesn't read YAML. **Negative:** - Any change to install behaviour has to land in both files at once (tribal-knowledge #11). The pair-edit invariant is real but has not yet caused a production incident. - Build-args are stringly-typed, so a typo on either side fails late — at install time inside the Docker build. **Neutral:** - The "detection in Groovy, execution in Dockerfile" split is mirrored elsewhere in `devops-lib` (e.g. Maven, Go); Node just happens to be the most config-driven and therefore the most visible example. ## Constraints - The package-manager choice has to be visible at Docker-build time inside the container; build-args are the cleanest way to inject it. - The library must support repos that build locally (no Jenkins, no `config.yaml`) for developer ergonomics. ## Current Assessment - **Still appropriate** — the split works, the override knob is being used as intended, and no incident has surfaced. A future hardening could add a CI check that any PR touching the install logic on one side also touches the other, but it is not load-bearing today. ## Related Decisions None directly. The "detection in Groovy, execution in container" split is a pattern repeated in other build stages (Maven, Go), but each has its own per-language ADR scope. ## Notes - Key files: `src/com/meesho/stages/buildNode.groovy`, `resources/com/meesho/node-Dockerfile` - `npm_install_arg` in `config.yaml` is a documented public extension point — see service-team usage in #devops-tech (Nov 2025) for the `--legacy-peer-deps` case. - Discovery id: PATTERN-2