Catch Jenkinsfile syntax errors before they break your CI.
jenkinsfilelint validates your Declarative Pipeline syntax via Jenkins's
/pipeline-model-converter/validate
endpoint. It's primarily a pre-commit hook, but also
works as a standalone CLI tool.
π Read the official blog post for the story behind this tool.
- Quick Start
- Pre-commit Hook
- CLI
- Filtering files
- Configuration
- Security
- How It Works
- Requirements
- Contributing
- License
pip install jenkinsfilelintThen add the pre-commit hook (see below) or use the CLI directly.
Add the hook to your .pre-commit-config.yaml and install. Once configured,
every commit that touches a Jenkinsfile is automatically validated.
# .pre-commit-config.yaml
repos:
- repo: https://github.com/jenkinsci/jenkinsfilelint
rev: # use the latest or a specific version, e.g. v1.4.0
hooks:
- id: jenkinsfilelintSet credentials via environment variables, then install:
export JENKINS_URL=https://jenkins.example.com
export JENKINS_USER=your-username
export JENKINS_TOKEN=your-api-token
pip install pre-commit
pre-commit install# .pre-commit-config.yaml
repos:
- repo: https://github.com/jenkinsci/jenkinsfilelint
rev: # use the latest or a specific version, e.g. v1.4.0
hooks:
- id: jenkinsfilelint
args: ["--local"]Docker (or Podman) is the only requirement β no credentials needed:
pip install pre-commit
pre-commit installThe first commit pulls a minimal Jenkins container (~20β40s cold start). Subsequent commits reuse the running container and complete in milliseconds.
Important
The pre-built image includes plugins for the most common Declarative
Pipeline patterns (see full list). If your production
Jenkins has additional plugins (e.g., kubernetes), local mode may still
report false positives for those constructs. For full fidelity, use remote
mode pointing at your real Jenkins, or build a custom image
that mirrors your production plugin set.
When you're done, stop the container:
jenkinsfilelint server stopA valid file passes silently:
git commit -m "Update Jenkinsfile"
jenkinsfilelint..........................................................PassedA syntax error blocks the commit with a clear message:
git commit -m "Update Jenkinsfile"
jenkinsfilelint..........................................................Failed
- hook id: jenkinsfilelint
- exit code: 1
Errors encountered validating Jenkinsfile:
WorkflowScript: 17: Expected a step @ line 17, column 11.
test
^Fix the error and re-commit.
You can also run jenkinsfilelint directly on any file:
pip install jenkinsfilelint
jenkinsfilelint Jenkinsfile
jenkinsfilelint Jenkinsfile Jenkinsfile.prod tests/Jenkinsfile
jenkinsfilelint --local JenkinsfileUse --include (whitelist) and --skip (blacklist) to control which files are validated:
# Only validate Jenkinsfiles
jenkinsfilelint --include 'Jenkinsfile*' Jenkinsfile src/Utils.groovy
# Exclude shared-library helper classes
jenkinsfilelint --skip '*/src/*.groovy' --skip 'vars/*.groovy' Jenkinsfile src/Utils.groovyThese work in pre-commit too:
Exclude non-pipeline Groovy files (shared library helpers):
- id: jenkinsfilelint
args: ["--skip=*/src/*.groovy", "--skip=vars/*.groovy"]Only validate files matching specific patterns:
- id: jenkinsfilelint
args: ["--include=Jenkinsfile*", "--include=pipelines/*.groovy"]You can also combine both β --include narrows first, then --skip removes from that set:
- id: jenkinsfilelint
args: ["--include=Jenkinsfile*", "--skip=*/src/*.groovy"]Supply credentials via environment variables (recommended) or CLI flags:
| Env Variable | CLI Flag | Required |
|---|---|---|
JENKINS_URL |
--jenkins-url |
Yes * |
JENKINS_USER |
--username |
No ** |
JENKINS_TOKEN |
--token |
No ** |
JENKINSFILELINT_SERVER_IMAGE |
β | No |
* Not required in --local mode.
** Only required if your Jenkins requires authentication (not used in --local mode).
Tip
Even if your Jenkins allows anonymous access for validation, using an API token is recommended for production setups.
CLI flags override env vars. There is no config file.
By default, --local mode uses the official image
ghcr.io/jenkinsci/jenkinsfilelint-server:latest, which includes the
following plugins to cover common Declarative Pipeline constructs:
| Plugin | Common pattern enabled |
|---|---|
docker-workflow |
agent { docker 'β¦' }, docker.image('β¦') |
git |
git url: 'β¦' |
credentials-binding |
withCredentials([β¦]) { β¦ } |
timestamper |
options { timestamps() } |
ws-cleanup |
post { always { cleanWs() } } |
pipeline-utility-steps |
readJSON, readYAML, findFiles |
This list is a curated starting point β not exhaustive. If your Jenkinsfile uses a plugin not listed here (e.g.
kubernetes,pipeline-github-lib), please open an issue to propose adding it, or use a custom image (see below).
Build a custom image matching your production Jenkins setup and point to it
via JENKINSFILELINT_SERVER_IMAGE:
# Export plugin list from your Jenkins (Script Console or Jenkins CLI)
# and generate plugins.txt + a Dockerfile, then:
docker build -t my-company/jenkinsfilelint-server:custom .
JENKINSFILELINT_SERVER_IMAGE=my-company/jenkinsfilelint-server:custom \
jenkinsfilelint --local JenkinsfileThe existing Dockerfile and plugins.txt are a good starting template β fork them and adjust the plugin list to match your production Jenkins.
A full Jenkins plugin list can be 100+ entries, which increases build time and image size. Only add what you need.
Warning
Never hardcode credentials in config files β use environment variables.
- Never put
--tokenor--usernamein.pre-commit-config.yamlβ use environment variables. - Use an API token, not your password.
- A regular user token with read access is sufficient β no need for admin privileges.
jenkinsfilelint POSTs your Jenkinsfile to Jenkins's
/pipeline-model-converter/validate endpoint and reports whether the syntax is
valid. That's it β it only answers: "Will Jenkins accept this syntax?"
- Remote mode: validates against your existing Jenkins server using the URL and credentials you configure.
- Local mode (
--local): automatically starts a lightweight Jenkins container (via Docker or Podman) and validates against it. The container is reused across runs for near-instant validation.
- Python 3.10+
- For remote mode: a Jenkins server with the Pipeline plugin installed
- For
--localmode: Docker or Podman
See CONTRIBUTING.md.
MIT β see LICENSE.
