How do you configure caching and artifacts in Bitbucket Pipelines to optimize build performance?
Quick Answer
Caches persist downloaded dependencies between pipeline runs (e.g., npm, pip, Maven packages), while artifacts pass files between steps within a single pipeline run. Caches are defined in the 'definitions' section and referenced by name; artifacts use glob patterns to specify which files to carry forward.
Detailed Answer
Caches and artifacts solve two different problems, and confusing them is like mixing up a pantry and a lunchbox. A pantry (cache) stores ingredients you reuse across many meals (pipeline runs). A lunchbox (artifact) carries your prepared food from the kitchen (step 1) to the office (step 2) on the same day. You would never put a sandwich in the pantry or store flour in a lunchbox.
Caches in Bitbucket Pipelines store directories between pipeline runs so that dependency installation steps do not start from scratch every time. Bitbucket provides pre-defined caches for common tools: 'node' caches node_modules, 'pip' caches Python packages, 'maven' caches the .m2 directory, and 'docker' caches Docker layers. You can also define custom caches in the 'definitions' section, specifying any directory path. Caches are keyed by name and are valid for seven days. If the cache is older than seven days or if the pipeline configuration changes the cache definition, Bitbucket rebuilds it.
Artifacts work differently. They are files produced by one step that need to be consumed by a subsequent step in the same pipeline run. When a step defines artifacts using glob patterns (e.g., dist/**), Bitbucket uploads those files at the end of the step and downloads them at the beginning of the next step. Artifacts are temporary and only live for the duration of the pipeline run. The maximum artifact size is 1 GB per step. Unlike caches, artifacts preserve file permissions and directory structure exactly as they were when the step completed.
In production, a well-optimized pipeline combines both mechanisms strategically. The first step restores the npm cache, runs npm ci (which is faster when cached packages are available), and produces a built dist/ folder as an artifact. The next step skips the install entirely, picks up the dist/ artifact, and runs deployment. This pattern can cut a 10-minute build down to 3 minutes. Teams also use the 'docker' cache for Docker layer caching, which dramatically speeds up image builds by reusing unchanged layers. For monorepos, custom caches for specific subdirectory dependencies (e.g., services/auth/node_modules) prevent cache invalidation when unrelated services change their dependencies.
A gotcha that wastes hours: the pre-defined 'node' cache stores node_modules, but npm ci deletes node_modules before installing. This means the 'node' cache is useless with npm ci. Instead, define a custom cache for ~/.npm (the npm download cache), which npm ci does use. Similarly, the 'pip' cache stores ~/.cache/pip, not the virtual environment. Getting the cache path wrong means your builds appear to cache but never actually speed up. Another trap: artifacts are downloaded to the working directory, so if two steps produce artifacts with the same filename, the later download overwrites the earlier one.