How does Woodpecker CI use Docker and plugins?

Updated

Woodpecker CI runs every pipeline step inside a Docker container, and when a standard image can't do what you need, you extend the pipeline by building a plugin. That design is the core of how the engine executes work: instead of running commands directly on the host, each step is isolated in a container, and plugins are just containers with a defined interface that Woodpecker calls. This applies to any project where you want reproducible, isolated build steps and reusable custom logic.

Docker as the execution model

Woodpecker is based on Docker containers and uses them to execute pipeline steps. The practical consequence is that a step isn't a shell command running on the agent host — it's a container started from an image you specify, with your commands or the image's entrypoint running inside it.

This gives you a few concrete properties:

  • Isolation per step. Each step gets its own container, so tool versions, environment variables, and filesystem changes don't leak between steps unless you explicitly share them (for example through a workspace volume).
  • Reproducibility. The image tag pins the environment. A step that passes on one agent should behave the same on another, because the container is the unit of execution rather than the host's installed toolchain.
  • Image choice as configuration. Selecting a language runtime, a database client, or a build tool is mostly a matter of picking the right image for that step.

A typical pipeline therefore looks like a sequence of steps, each naming an image and the commands to run inside it. The agent pulls the image, starts the container, executes the step, and reports the result back.

When a normal Docker image isn't enough

The documented boundary is explicit: if you need more than a normal Docker image, you can create plugins to extend the pipeline features. So the decision point is whether an existing image plus a command list covers your need.

Use a plain image when:

  • The task is "run these commands with this toolchain" (build, test, lint, package).
  • The behavior is fully described by the image's contents and the commands you pass.
  • You don't need to react to Woodpecker's pipeline metadata in a structured way.

Build a plugin when:

  • You want reusable logic that other pipelines can call with parameters rather than copy-pasted commands.
  • The step needs to integrate with Woodpecker's execution context in a defined way.
  • You're packaging a capability (deploy target, notification channel, artifact handler) that should behave consistently across projects.

How plugins extend the pipeline

A plugin in Woodpecker is essentially a container with a defined contract: Woodpecker runs it as a step and passes configuration in, and the plugin performs its work and returns a result. Because the mechanism is container-based, anything you can package into an image can become a plugin.

The practical workflow is:

  1. Identify the repeated or specialized task that a plain image plus commands handles awkwardly.
  2. Package it as a container image that reads its configuration from the environment or step settings.
  3. Reference it as a step in the pipeline, supplying the settings for that particular use.
  4. Verify by running the pipeline and checking that the plugin step receives its inputs and produces the expected effect (artifact, deployment, message, exit status).

The benefit of this over inlining commands is reuse and consistency: the logic lives in one image, and every pipeline that needs it calls the same versioned artifact.

Multi-workflow pipelines

Woodpecker also allows you to easily create multiple workflows for your project, and they can even depend on each other. Combined with container-based steps, this means you can structure a pipeline as several workflows — for example separate build, test, and deploy flows — with explicit dependencies between them, each workflow made of containerized steps and plugin steps.

What this buys you

  • Portability. The execution environment travels with the pipeline definition as image references, not as host setup.
  • Extensibility without forking. Plugins let you add capability through images rather than modifying the engine.
  • Composability. Multiple workflows with dependencies let you model real delivery stages instead of one long linear script.

Choosing between an image and a plugin

Situation Use
Run standard commands with a known toolchain A normal Docker image
Need behavior beyond a normal image A plugin
Logic reused across many projects A plugin
One-off commands specific to a single repo A normal Docker image
Multiple related stages with ordering Multiple workflows with dependencies

If your step is "install dependencies and run tests," an image is enough. If your step is "publish to our internal system in a standard way that every repo should follow," that's the case the docs point to for building a plugin.

Woodpecker is open source and free, and because the source is open you can contribute to help evolve the project — which also means you can inspect how the container and plugin execution actually works if you need to go deeper than the documented behavior.