Custom Pipeline Steps in Jenkins: Building Your Own CI/CD Building Blocks
A complete, beginner-friendly guide to understanding, designing, and safely using custom pipeline steps in Jenkins — from the ground up, with no prior Jenkins experience assumed.
Imagine you’re furnishing a house using only a basic toolbox — a hammer, a screwdriver, a wrench. You can build almost anything with these, but every single time you need to hang a picture frame, you repeat the same five steps: find a stud, mark the spot, drill a pilot hole, insert the anchor, drive the screw. Now imagine you had a single tool that did all five steps the moment you pressed a button — a “hang-picture-frame” tool. That’s exactly what a custom pipeline step is in Jenkins: a small, purpose-built tool that wraps up a repeated sequence of basic actions into one reusable command. This tutorial walks through what these steps are, how Jenkins actually runs them behind the scenes, how to design them well, and how to avoid the mistakes that trip up almost every team the first time they build one.
1What Is a Jenkins Pipeline, Really?
Before understanding custom steps, you need a clear mental picture of the pipeline they live inside.
The assembly line analogy
A Jenkins Pipeline is best understood as an automated assembly line for software. Just as a car factory takes raw metal and, through a fixed sequence of stations, turns it into a finished car, a Jenkins Pipeline takes raw source code and, through a fixed sequence of stages, turns it into a tested, packaged, and deployed application. Each station on the assembly line does one job — welding, painting, installing seats — and each stage in a pipeline does one job too, such as compiling code, running tests, or pushing a container image.
Think of Jenkins itself as the factory floor manager. It doesn’t weld or paint anything itself — it reads a instruction sheet (called a Jenkinsfile) and directs workers (called steps) to do each job in order. Every individual instruction on that sheet — “checkout the code,” “run the tests,” “send a Slack message” — is a step.
Declarative versus scripted pipelines
Jenkins supports two ways of writing this instruction sheet. A declarative pipeline is like a fill-in-the-blanks form: it has a fixed structure (stages, steps, post-actions) that is easy to read and validate. A scripted pipeline is like a blank sheet of paper written in the Groovy programming language, giving you total freedom but demanding more discipline. Custom steps work with both styles, because a custom step is simply a new word that gets added to Jenkins’s vocabulary — it can be called from either kind of pipeline exactly like a built-in instruction.
checkout
Pulls source code from a version control system such as Git.
sh
Runs a shell command on the build agent.
archiveArtifacts
Saves build output files so they can be downloaded later.
deployToStaging
A step your team invents that bundles several built-in steps into one reusable action.
Every one of the built-in steps above ships with Jenkins out of the box. A custom step is something your organization defines itself, but once it exists, it looks and behaves exactly like a built-in one to whoever writes a Jenkinsfile — that indistinguishability is the entire point.
2Why Custom Pipeline Steps Exist
Every reusable tool exists because doing the same thing manually, over and over, is expensive and error-prone.
The problem of copy-pasted logic
Picture a company with forty different applications, each with its own Jenkinsfile. Every one of those forty files contains a nearly identical block of instructions for building a Docker image, scanning it for vulnerabilities, tagging it with the current date and commit hash, and pushing it to a private registry. That’s roughly fifteen lines of logic, copy-pasted forty times. The moment the security team wants to add a new scanning tool, someone has to hunt down and update all forty copies — and inevitably, a few get missed.
Teams often notice repeated pipeline logic but keep copy-pasting it “just this once” for months or years, because writing a proper custom step feels like a bigger task than it actually is.
Custom steps as the fix
A custom step solves this by moving that fifteen-line block into one place, in a special code repository called a Shared Library. Every Jenkinsfile that needs it now calls the custom step by name — a single line — instead of repeating the logic. When the security team wants to add a new scanning tool, they update the custom step’s definition exactly once, and every one of those forty pipelines picks up the change automatically the next time it runs.
Beyond duplication: enforcing standards
Custom steps aren’t only about saving keystrokes. They are also how a platform or DevOps team enforces organization-wide standards without policing every pipeline by hand. If a custom step called deployToProd always requires a manual approval and always records the deployment in an audit log, then no team can accidentally skip those safeguards — the safeguards are baked into the tool itself, not left to each engineer’s memory.
Compliance as Code
A financial services company built a custom step called releaseWithSignOff that automatically requires two named approvers before any production deployment, satisfying an audit requirement without a single manual checklist.
Consistent Notifications
A retail company built a custom step called notifyTeam so that every single pipeline — regardless of which engineer wrote it — sends failure alerts to the same Slack channel in the same format.
3The Anatomy of a Custom Step
A custom step is made of a handful of well-defined pieces that fit together like a small appliance.
The Shared Library: the toolbox itself
All custom steps live inside a special Git repository called a Shared Library. Jenkins is told, in its global configuration, where this repository lives. Once registered, any Jenkinsfile anywhere in the organization can import it and immediately gain access to every custom step defined inside — much like installing an app on your phone gives you access to every feature that app offers.
If Jenkins is the factory floor, the Shared Library is the factory’s central tool crib — the storage room where all the specialized, purpose-built tools are kept. Any worker on the floor can walk over, sign out a tool by name, and use it, without needing to know how the tool was manufactured.
The “vars” folder: where step names live
Inside the Shared Library, a specific folder holds the actual custom steps. Each file in that folder represents exactly one custom step, and the file’s name becomes the step’s name that people type in their Jenkinsfile. This naming rule is not a convention — it is how Jenkins locates and recognizes a custom step at all.
| Piece | Role | Everyday Comparison |
|---|---|---|
| Shared Library repository | Stores every custom step for the organization | A shared tool crib |
| vars folder | Contains one file per custom step | A labeled shelf of individual tools |
| Step definition file | Describes what the step does when called | The instruction booklet glued to a tool |
| Jenkinsfile | Calls the custom step by name | A worker picking up a tool and using it |
Parameters: giving instructions to the tool
Just like a real tool often has settings — a drill has a speed dial, a thermostat has a temperature knob — a custom step can accept parameters. A step named deployApp might accept parameters for which environment to deploy to and which version number to use, so the same reusable tool can be pointed at different targets without being rewritten.
Name
What people type in the Jenkinsfile to invoke the step.
Parameters
Optional inputs that customize the step’s behavior each time it runs.
Body
The internal sequence of built-in steps the custom step performs.
Return Value
Optional information the step hands back to the pipeline that called it.
4How Jenkins Executes a Custom Step Internally
Understanding the internal mechanics demystifies what feels like magic the first time you see it work.
The moment a pipeline starts
When a pipeline run begins, Jenkins first reads the Jenkinsfile and notices any Shared Library import declared at the top. It then checks out that library’s repository — behind the scenes, just like checking out any other Git repository — into a temporary location on the controller. This happens before a single line of your actual pipeline logic executes.
sequenceDiagram
participant J as Jenkinsfile
participant C as Jenkins Controller
participant L as Shared Library Repo
participant A as Build Agent
J->>C: Declare library import
C->>L: Checkout library source
L-->>C: Library files loaded
J->>C: Call custom step by name
C->>C: Match name to vars file
C->>A: Run underlying built-in steps
A-->>C: Return step result
C-->>J: Continue pipeline execution
Name resolution: how Jenkins finds the right file
When your Jenkinsfile calls a custom step, Jenkins doesn’t search your whole codebase — it looks specifically inside the vars folder of every currently loaded Shared Library for a file whose name matches. This is why the file-naming rule from the previous chapter is so strict: a typo in the file name, or the step name in the Jenkinsfile, breaks the connection completely, and Jenkins reports that it cannot find the step.
Because a custom step is matched purely by file name, two Shared Libraries loaded into the same pipeline must never define a step with the same name — Jenkins has no reliable way to know which one you meant.
Where the code actually runs
It’s a common misconception that a custom step runs “on the controller” in some special, separate way. In reality, once Jenkins has located the step’s definition, it executes the built-in steps written inside that definition exactly as if you had typed them directly into your Jenkinsfile — on whichever build agent your pipeline stage is currently assigned to. The custom step is a layer of indirection, not a different execution environment.
5Data Flow and the Pipeline Lifecycle
Custom steps don’t operate in isolation — they read from and write into a shared pipeline context.
Inputs flowing in
Data reaches a custom step through three main channels: the parameters explicitly passed when it’s called, environment variables already set in the pipeline (such as the build number or branch name), and files already present in the workspace, which is the folder on the build agent where the checked-out source code lives. A well-designed custom step is explicit about which of these it relies on, rather than silently assuming a variable will exist.
Pipeline starts
Jenkins checks out the source code and loads any Shared Libraries into the workspace context.
Custom step is called
Parameters are passed in, and Jenkins resolves the step name to its definition file.
Step reads context
The step reads environment variables, workspace files, and its own parameters to decide what to do.
Step performs actions
Built-in steps run — shell commands, file operations, notifications — using that context.
Step returns and pipeline continues
Any return value or modified workspace state is available to the next stage in the pipeline.
Outputs flowing back out
A custom step can hand information back to the pipeline in two ways: by returning a value directly, similar to how a vending machine hands back your snack after you press a button, or by leaving files or modified state in the shared workspace for later stages to pick up, similar to leaving a note on a shared office whiteboard for the next shift.
A relay race is a good picture of this data flow. Each runner (stage) receives the baton (workspace and environment variables) from the previous runner, does their leg of the race (executes steps), and hands the baton — possibly with something new attached to it — to the next runner.
The lifecycle from the controller’s point of view
From Jenkins’s own perspective, a pipeline run moves through distinct phases: queued, checked out, library-loaded, executing, and post-actions. Custom steps typically operate during the executing phase, but a well-designed Shared Library can also hook into post-actions — for example, a custom step that always sends a summary notification regardless of whether the pipeline succeeded or failed.
6Types of Custom Steps and Where They’re Used
Not all custom steps solve the same kind of problem — they fall into a few recognizable families.
Build and Packaging Steps
Wrap up the exact sequence of commands needed to compile a specific type of application — for example, a step that knows how to build a Java service using a particular internal build tool configuration.
Testing and Quality Gate Steps
Run a standard suite of automated tests and quality checks, then fail the pipeline immediately if results fall below an agreed threshold, without every team needing to know the exact thresholds themselves.
Deployment Steps
Encapsulate the full sequence of actions needed to safely release an application to a given environment, often including approval gates, health checks, and rollback logic.
Notification and Reporting Steps
Standardize how build results are communicated — to chat tools, dashboards, or ticketing systems — so every team’s pipeline “speaks” in the same format.
Security and Compliance Steps
Bundle mandatory scanning, credential handling, or audit logging so that these requirements cannot be accidentally skipped by an individual pipeline author.
Choosing the right granularity
A common design question is how much a single custom step should do. A step that is too narrow — for example, one that only runs a single shell command — barely saves any typing and adds unnecessary indirection. A step that is too broad — for example, one giant step called doEverything that builds, tests, scans, and deploys all in one call — becomes rigid and hard to reuse when a team only needs part of that behavior. The sweet spot is usually a step that represents one coherent, named business action, such as “build,” “scan,” or “deploy,” each usable independently.
runShellCommand
Offers almost nothing over just typing the shell command directly.
doEverything
Forces teams to accept behavior they don’t need just to get the one part they do.
buildDockerImage
Represents one clear, reusable action that many pipelines genuinely share.
scanForVulnerabilities
Can be combined with other well-scoped steps in whatever order a pipeline needs.
7Advantages and Trade-offs
Custom steps are powerful, but like any abstraction, they come with real costs alongside their benefits.
Advantages
- Eliminates duplicated logic across many Jenkinsfiles
- Centralizes updates — fix or improve logic in one place
- Enforces organizational standards automatically
- Makes Jenkinsfiles shorter and easier to read for application teams
- Allows a platform team to evolve internal implementation details without breaking pipeline authors
Disadvantages / Trade-offs
- Adds a layer of indirection that can make debugging harder for newcomers
- Introduces a dependency on the Shared Library’s availability and version
- Poorly documented custom steps become confusing “black boxes”
- Changes to a widely used step can unintentionally break many pipelines at once
The hidden cost of indirection
When something goes wrong inside a built-in step like sh, the error message points directly at the command that failed. When something goes wrong inside a custom step, an engineer unfamiliar with the Shared Library first has to discover that a custom step even exists, then locate its source file, then read through its internal logic to find the real cause. This is not a reason to avoid custom steps — but it is a reason to invest in clear naming and documentation, covered in a later chapter.
Every custom step you add makes individual Jenkinsfiles simpler, but makes the overall system slightly more complex, because now there are two places to understand: the Jenkinsfile and the Shared Library.
The blast radius problem
Because a single custom step might be called from dozens or hundreds of pipelines across an organization, a bug introduced into that one step’s definition can simultaneously break every single one of them the next time they run. This “blast radius” is the central trade-off of centralization: the same property that makes fixes easy also makes mistakes expensive.
8Security Considerations
Because custom steps often run with elevated trust, they deserve extra scrutiny.
The sandbox and why it matters
Jenkins normally runs pipeline scripts inside a restricted environment called the Groovy sandbox, which blocks potentially dangerous operations unless an administrator explicitly approves them. Shared Library code, however, is often granted more trust than sandboxed pipeline scripts, especially when marked as coming from a trusted source repository. This means a poorly reviewed custom step can potentially perform actions a normal Jenkinsfile author could never do directly.
Think of the sandbox like airport security for carry-on luggage, and a trusted Shared Library like a courier with a special badge that skips the usual line. That badge is convenient, but it means the courier’s own bag needs to be checked far more carefully before the badge is issued.
Credential handling inside custom steps
A frequent and risky pattern is a custom step that needs access to a secret — a deployment key, an API token, a database password. The safe approach is for the step to retrieve that secret through Jenkins’s built-in credentials mechanism at the moment it’s needed, and never to print it, log it, or return it as part of its output. Because a custom step’s internal logic is invisible to whoever calls it, this discipline must be enforced by the people who write and review the Shared Library, not by every downstream pipeline author.
Treat every custom step that touches credentials as if it were production code, because from a security standpoint, it effectively is — it runs with real access on real infrastructure.
Who can change the Shared Library?
Because updating the Shared Library’s source repository can change the behavior of every pipeline that uses it, write access to that repository should be as tightly controlled as access to production deployment credentials. A change review process — requiring at least one other engineer’s approval before merging — is standard practice for exactly this reason.
Problem
Anyone on the engineering team has direct, unreviewed write access to the Shared Library repository.
Why It’s Harmful
A single unreviewed change can silently alter the behavior of every pipeline across the organization, including production deployment pipelines.
Correct Approach
Require pull-request review from a designated platform or DevOps owner before any change to the Shared Library is merged.
9Monitoring, Logging, and Metrics
A custom step that fails silently, or fails without explanation, undermines the trust that makes it worth using.
What good logging inside a step looks like
A well-behaved custom step should clearly announce what it is doing at each meaningful stage — for example, printing a line indicating which environment it’s about to deploy to, before it does so. This isn’t just courtesy; when a pipeline fails, this log output is often the first and only clue an engineer has about what the step attempted and how far it got.
Announce Intent
Log what the step is about to do before doing it.
Log Key Parameters
Show which environment, version, or target the step is operating on — excluding secrets.
Confirm Success
Print a clear confirmation line when the step completes successfully.
Fail Loudly and Clearly
When something goes wrong, produce a message that names the actual cause, not a generic error.
Tracking usage across the organization
Because a single custom step may be invoked by hundreds of pipelines, some organizations instrument their most critical steps to emit a small usage metric each time they run — recording which team called it, how long it took, and whether it succeeded. Over time, this data answers questions a platform team genuinely needs to answer: which steps are actually used, which ones are safe to retire, and which ones are becoming a reliability bottleneck.
graph LR
A[Custom Step Runs] --> B[Emits Duration Metric]
A --> C[Emits Success/Failure Metric]
A --> D[Emits Calling Team Label]
B --> E[Metrics Dashboard]
C --> E
D --> E
E --> F[Platform Team Reviews Trends]
Alerting on step-level failures
For steps considered critical — deployment or security-scanning steps, for example — some organizations wire up an alert that fires whenever the step fails at an unusually high rate compared to its historical baseline, rather than waiting for individual teams to notice and complain. This shifts monitoring from reactive to proactive, catching a broken Shared Library update within minutes instead of days.
10Design Patterns and Anti-Patterns
Some approaches to writing custom steps age well; others quietly become liabilities.
Pattern: sensible defaults with explicit overrides
A well-designed custom step should work correctly when called with the bare minimum of information, using sensible default values for everything else, while still allowing an advanced caller to override any individual default when they genuinely need to. This mirrors how a good kitchen appliance has a “quick start” button for common cases and a manual settings menu for everyone else.
Good Pattern: Layered Configuration
A deployment step defaults to standard health-check timing and rollback behavior, but allows a caller to pass a longer timeout for an unusually slow-starting service without needing to change the step itself.
Anti-pattern: silent magic
A custom step that reads hidden environment variables or makes undocumented assumptions about the shape of the workspace — without clearly stating these requirements anywhere — creates a trap for anyone who calls it without knowing this folklore. When it fails, the failure looks unrelated to its actual cause, and the engineer debugging it has no way to guess the real requirement.
Problem
A custom step silently depends on an environment variable or file that isn’t documented anywhere and isn’t validated at the start of the step.
Why It’s Harmful
Callers who don’t know the hidden requirement get confusing failures that look unrelated to the missing piece, wasting significant debugging time.
Correct Approach
Validate all required inputs explicitly at the very start of the step, and fail immediately with a clear message naming exactly what’s missing.
Pattern: composability over monoliths
As mentioned in Chapter 6, favoring several small, focused steps that can be combined in different orders tends to age better than one large step that tries to handle every scenario. A pipeline author who only needs the scanning behavior, not the deployment behavior, should be able to use just the scanning step — a monolithic step forces them to accept, or awkwardly work around, behavior they don’t want.
Anti-pattern: version drift without a strategy
If pipelines don’t pin which version of the Shared Library they use, an update meant for one team’s pipelines can unexpectedly change behavior for every other team on the very next build. A deliberate versioning strategy — where pipelines can choose to stay on a known-good version or opt into the latest — avoids this instability.
11Best Practices and Common Mistakes
These are the lessons most teams learn the hard way — you don’t have to.
Documentation is not optional
Because a custom step hides its internal logic behind a simple name, the only way most people will ever learn how to use it correctly is through documentation placed right alongside its definition — describing its required and optional parameters, what it returns, and what it assumes about the environment it runs in.
A short comment block at the top of each step’s definition file, listing its parameters and a one-line description, prevents the vast majority of “how do I use this?” questions.
Test custom steps like real software
Because a Shared Library is ordinary source code, it can and should be tested before being trusted by every pipeline in the organization — for example, by running it against a staging copy of a real pipeline before merging a change, rather than discovering problems only when production pipelines start failing.
Validate Inputs Early
Check required parameters at the very top of the step and fail with a clear message if they’re missing.
Keep Steps Focused
One step, one clear job — combine steps in the Jenkinsfile rather than inside the step itself.
Version Deliberately
Let pipelines choose which version of the library to use, rather than always pulling the latest unreviewed change.
Review Changes Like Production Code
Require peer review before merging changes to the Shared Library, since the blast radius is organization-wide.
Common mistake: naming steps after implementation instead of intent
A step named after what it technically does internally — for example, something obscure referencing an internal tool’s name — is far less useful than a step named after the business intent it fulfills, such as deployApp or runSecurityScan. Good naming means a new engineer can guess what a step does before ever opening its source file.
Common mistake: forgetting about failure paths
It’s easy to design a custom step around the happy path — everything working — and forget to think through what should happen when a dependency is unavailable, a credential is expired, or a network call times out. A step that fails ungracefully, leaving the pipeline in a confusing half-finished state, is worse than no custom step at all.
12Real-World and Industry Examples
Seeing how different kinds of organizations actually use this pattern makes the abstract concrete.
A Large E-Commerce Platform
With hundreds of microservices, the platform team maintains a Shared Library containing steps like buildService and deployService that every service team calls identically, letting the platform team roll out new container-scanning requirements across the entire company in a single Shared Library update.
A Regulated Financial Institution
Custom steps encode mandatory compliance controls — dual approval, immutable audit logging, and encrypted secret retrieval — directly into the deployment step itself, so that compliance is guaranteed by the tooling rather than relying on every engineer remembering the policy.
A Mobile App Company
A custom step called publishToAppStores hides the genuinely complicated, multi-platform submission process behind one simple call, so mobile engineers can focus on app features instead of the intricacies of store submission tooling.
An Open-Source Foundation
Shared custom steps standardize how dozens of independently maintained open-source projects run their continuous integration checks, ensuring a consistent quality bar across projects maintained by entirely different volunteer teams.
A pattern across all four examples
In every case above, the underlying motivation is the same: a central team wants confidence that a critical, repeated process happens correctly and consistently everywhere, without personally reviewing every single pipeline by hand. Custom pipeline steps are, at their heart, a scalable way to turn tribal knowledge and manual policy into something the system itself enforces.
13Frequently Asked Questions
Straightforward answers to the questions almost every newcomer asks.
No. Most custom steps are simply a sequence of built-in steps you would have written directly in a Jenkinsfile anyway, wrapped inside a named file. Basic familiarity with how pipelines work is enough to get started; deep Groovy expertise only becomes necessary for advanced logic.
Yes. Custom steps can call one another just as they call built-in steps, which is exactly how the composability pattern from Chapter 10 works in practice — small steps combining into larger ones.
This creates ambiguity that Jenkins resolves based on load order, which is fragile and easy to get wrong. As covered in Chapter 4, the safest approach is to simply avoid duplicate step names across libraries used together.
Not necessarily. As discussed in Chapter 6, a step so small that it barely saves any effort adds indirection without much benefit. A useful rule of thumb is to create a custom step once the same logic has genuinely been copy-pasted three or more times.
Most Shared Library setups allow a pipeline to point at a specific branch or version of the library instead of the default one, which lets you test a change against a single real pipeline before merging it for everyone else, as recommended in Chapter 11.
Yes — that cross-team reuse is the primary reason custom steps exist at all, as explained in Chapter 2. Any pipeline that loads the Shared Library gains access to every step it defines, regardless of which team owns that pipeline.
14Summary and Key Takeaways
Custom pipeline steps turn Jenkins from a tool that only understands generic, built-in instructions into a tool that speaks your organization’s own vocabulary — deploy, scan, notify, release — expressed as single, reusable words in a Jenkinsfile. Underneath that simplicity sits a Shared Library, a specially named folder structure, and the same built-in steps you’d otherwise type by hand, executed on the same build agents in the same way. The real value of custom steps isn’t magic; it’s disciplined reuse — one place to fix logic, one place to enforce security and compliance, and one place to keep every pipeline in an organization speaking the same language.
Key Takeaways
- A custom step is a named wrapper — it bundles a repeated sequence of built-in steps behind one reusable name, defined inside a Shared Library’s vars folder.
- Execution isn’t special — a custom step runs on the same build agent, using the same underlying mechanics, as if its logic were typed directly into the Jenkinsfile.
- Naming is the connection point — Jenkins matches a called step to its definition purely by file name, so consistent naming across libraries matters a great deal.
- Centralization cuts both ways — one fix reaches every pipeline instantly, but so does one mistake, which is why review discipline for the Shared Library matters.
- Security deserves special attention — Shared Library code often runs with more trust than an ordinary pipeline script, especially around credentials.
- Good design favors small, composable steps — with sensible defaults, explicit input validation, and clear documentation, over large, rigid, all-in-one steps.
- Real organizations use custom steps to enforce policy — turning compliance, security, and quality requirements into something the system guarantees, not something every engineer has to remember.