How do Bitbucket Pipes work and when should you write a custom pipe versus using a built-in one?
Quick Answer
Bitbucket Pipes are pre-packaged CI/CD integrations that run as Docker containers inside pipeline steps, abstracting complex deployment and integration tasks into simple YAML declarations. You should use built-in pipes for standard tasks (AWS, Azure, Slack) and write custom pipes when your organization has proprietary deployment targets or internal tooling.
Detailed Answer
Think of Pipes as power tools in a workshop. Instead of hand-cutting wood with a manual saw (writing 20 lines of shell script to deploy to AWS), you pick up the power saw (the atlassian/aws-s3-deploy pipe) and get the job done in three lines. Custom pipes are like building your own specialized tool when no off-the-shelf option fits your workbench.
Bitbucket Pipes are reusable Docker containers that encapsulate common CI/CD tasks. When you reference a pipe in your bitbucket-pipelines.yml, Bitbucket pulls the Docker image for that pipe, runs it with the variables you provide, and reports the result. Atlassian maintains a catalog of official pipes for major cloud providers (AWS, Azure, GCP), notification services (Slack, Microsoft Teams), and deployment platforms (Kubernetes, Heroku). Community-contributed pipes are also available through the Bitbucket Pipes marketplace. The syntax uses the 'pipe' keyword inside a step's script block, followed by the pipe identifier (e.g., atlassian/aws-ecs-deploy:2.0.0) and a variables block.
Under the hood, each pipe is a Docker image stored in Docker Hub or a public container registry. The pipe's entrypoint script reads the variables you pass, performs the task, and exits with a status code. Bitbucket treats a non-zero exit code as a step failure. Pipes run inside the same step, so they share the filesystem with your cloned repository and any preceding script commands. You can mix regular script commands and pipe invocations in the same step. The version tag (e.g., :2.0.0) is critical: it pins the pipe to a specific Docker image digest, ensuring reproducibility. Using ':latest' is discouraged because a pipe update could break your pipeline without warning.
In production, teams choose between built-in pipes and custom pipes based on their deployment targets. If you deploy to AWS ECS, the atlassian/aws-ecs-deploy pipe handles task definition updates, service deployments, and rolling restarts. But if your company uses an internal PaaS or a proprietary deployment API, you need a custom pipe. A custom pipe is a Docker image with an entrypoint script that receives variables and performs the task. You publish it to Docker Hub (or Bitbucket's container registry), and other teams in your workspace can use it by referencing your image. Custom pipes typically wrap internal CLIs, enforce deployment checklists, or integrate with in-house monitoring tools.
A gotcha to note: pipes run with the same permissions as the pipeline step, so any environment variables (including secured variables) are accessible to the pipe's Docker container. If you use a community pipe, you are trusting that container with your secrets. Always vet third-party pipes by reviewing their source code on Bitbucket, and prefer official Atlassian pipes or pinned versions of community pipes. Another common mistake is overusing pipes for simple tasks: if a task is a single curl command, writing it directly in the script is simpler and more transparent than introducing a pipe dependency.