put node_modules in cache, not artifacts. Define a cache block with key files set to your lockfile, so the cache invalidates exactly when dependencies change, and paths set to node_modules. Every job that needs dependencies gets them restored without an install step. Keep artifacts for what they are for: the built bundle, test reports, things downstream jobs or humans consume. If cache restores feel slow, check that your runners share a cache backend, and consider a private npm registry or proxy so the occasional cold install is fast too. Merging setup into the build stage is a workaround; the cache keyed on the lockfile is the durable fix.

Context: Stack Overflow #55983877 (top answer): a team ran npm install in every job because node_modules didnt survive between stages. The answers converge on the real distinction: cache is the mechanism for dependencies like node_modules, shared between jobs and pipelines to skip reinstalls, while artifacts are for build outputs you want to keep or pass downstream. Caching node_modules with a key on the lockfile means install only re-runs when dependencies actually change.