How do you configure multi-step Bitbucket Pipelines with parallel steps and conditional execution?
Quick Answer
Bitbucket Pipelines supports parallel steps within a stage using the 'parallel' keyword, allowing independent tasks like linting and testing to run concurrently. Conditional execution is achieved through step conditions, custom pipelines triggered manually, and branch-specific pipeline definitions.
Detailed Answer
Think of a multi-step pipeline like a restaurant kitchen. Some tasks happen sequentially (you must prep before you cook), but others happen in parallel (the salad station and grill station work simultaneously). Bitbucket Pipelines lets you model both patterns, cutting build times dramatically when you identify independent work.
Bitbucket Pipelines defines workflows in bitbucket-pipelines.yml using a hierarchy of pipelines, stages, and steps. A pipeline is a top-level trigger (default, branch, tag, pull request, or custom). Within a pipeline, steps run sequentially by default. To run steps in parallel, you wrap them in a 'parallel' block. Each parallel step still gets its own Docker container, but they execute simultaneously, sharing the same stage. Stages group sequential phases: for example, a 'Build' stage followed by a 'Test' stage, where the Test stage contains parallel steps for unit tests, integration tests, and linting.
Internally, Bitbucket allocates separate build containers for each parallel step, drawing from the same pool of build minutes. The maximum number of parallel steps depends on your plan: free plans allow up to 5 parallel steps, while premium plans allow up to 10. Each parallel step counts its own build minutes independently. Artifacts can flow forward between sequential stages but not between parallel steps in the same stage, since they finish at different times. The pipeline engine waits for all parallel steps to complete before advancing to the next stage; if any parallel step fails, the stage fails.
In production, teams use conditional logic to optimize pipeline behavior. The 'condition' key on a step can check the changeset to determine if the step should run. For example, you can configure a frontend test step to only execute when files in the src/frontend/ directory have changed, saving build minutes when only backend code is modified. Custom pipelines allow manual triggers with runtime variables, useful for on-demand tasks like database migrations, canary deployments, or generating reports. Branch-specific pipelines ensure that feature branches run lightweight checks while main and release branches run full test suites with deployment steps.
A gotcha that bites teams: parallel steps cannot share artifacts with each other. If step A generates test fixtures that step B needs, they must run sequentially or the fixtures must be pre-built in a prior stage. Another trap is the 'size' keyword for memory allocation: parallel steps each consume their own memory allocation (1 GB default, 2x with size: 2x), so running five 2x parallel steps uses 10 GB of your concurrent memory limit, which can cause queueing on lower-tier plans.