What Are Environment Variables in Jenkins?
The named values that every build can read. Learn what they are, which ones Jenkins gives you for free, how to create your own at different levels, how to handle secrets safely, how scope and precedence work, and how to avoid the classic mistakes.
Picture a busy workshop with a whiteboard on the wall. On the board are a few short notes: “Today’s date”, “Customer name”, “Box size: large”, “Delivery address”. Every worker glances at the board when they need a fact, so nobody has to ask the manager the same question a hundred times. If the address changes, the manager updates one line on the board, and everyone automatically uses the new one.
Environment variables are that whiteboard. They are named values, such as a build number or a target server, that are placed around a running program so that it can read them when needed. Jenkins fills the board with many useful notes for every build, and lets you add your own. Steps in your job can read those notes instead of having facts typed into them again and again.
In this guide you will learn what environment variables are, which ones Jenkins provides, how to create your own in Freestyle projects and in Pipelines, how scope decides which step can see which value, how to handle secrets without leaking them, how variables differ from parameters and credentials, and how to solve the puzzles that trip up almost every beginner. Every new word is explained the first time it appears.
1What Is an Environment Variable?
An environment variable is a named piece of text that a running program can look up by its name.
Let us build the idea from the ground up. A variable is a name attached to a value, like a label stuck on a jar. The label says “sugar”, and the jar holds the sugar. You can change what is inside the jar without changing the label. An environment is the set of surroundings a program runs in. So an environment variable is a labelled value that lives in the surroundings of a program, where the program can read it whenever it wants.
Every computer already has them. The variable PATH tells your terminal where to look for programs. The variable HOME names your personal folder. Programs read these quietly without asking you. Jenkins uses the same well-known mechanism: before it runs a step, it places a set of variables in the surroundings of that step. Your commands, scripts and tools can then read them by name.
Two facts are worth remembering right away. First, every environment variable is text. Even a number such as a build number is stored as a piece of text, and the program that reads it must convert it if it needs arithmetic. Second, environment variables are looked up at the moment of use, so changing one changes the behaviour of every step that reads it, without editing those steps.
Think of environment variables as the labelled sticky notes on a shared whiteboard. Any worker can read a note by its label. The manager can replace a note in one second, and everyone immediately uses the new value, without anyone rewriting their instructions.
2Why Environment Variables Matter
They keep jobs flexible, tidy and safe. Without them, every value would be typed directly into every step.
Imagine a build that deploys to a test server. Without variables, the server address is typed into ten different steps. When the address changes, you must find and fix all ten, and you will surely miss one. With a variable, the address lives in one place, and all ten steps read it. Change it once, and everything follows.
One place to change
A value defined once and read many times removes copy-and-paste errors and makes updates instant.
Same job, different settings
The same Pipeline can behave differently for test and production simply by supplying different values, without duplicating the whole job.
Awareness of context
Jenkins provides facts about the current build, such as its number, branch and workspace, so scripts can name files and messages correctly.
Safer secrets
Passwords and tokens can be handed to steps as variables during the build, instead of being written into scripts that everyone can read.
Portable scripts
A script that reads its settings from variables can run on a laptop, a test server and Jenkins, with only the values changing.
Readable pipelines
Meaningful names such as DEPLOY_TARGET explain intent better than a raw address scattered through the file.
A helpful rule of thumb: if you type the same value in more than two places, or if the value might change, or if it is secret, it probably deserves to be an environment variable.
3Built-in Variables Jenkins Gives You
Before you create anything, Jenkins already places many useful variables in every build.
| Variable | What it holds | A typical use |
|---|---|---|
BUILD_NUMBER | The number of this build, such as 42 | Naming a package or a report |
BUILD_ID | A build identifier, in recent versions the same as the number | Similar uses, mostly for older setups |
BUILD_URL | The web address of this build’s page | Linking to the build from a message |
BUILD_TAG | A text combining the job name and build number | Unique labels for files and images |
JOB_NAME | The full name of the job, including folders | Reports and notifications |
JOB_BASE_NAME | The short name of the job without folder path | Safe file names |
JOB_URL | The web address of the job | Linking to the job page |
WORKSPACE | The absolute folder path where the build works | Pointing tools at files inside the workspace |
NODE_NAME | The name of the machine running the build | Debugging differences between agents |
NODE_LABELS | The labels of that machine | Understanding where a build landed |
EXECUTOR_NUMBER | The slot number on that machine | Avoiding clashes when builds share a machine |
JENKINS_URL | The web address of the Jenkins server | Building links to other pages |
STAGE_NAME | The name of the current stage in a Declarative Pipeline | Messages that say which stage is running |
Variables added by plugins
Plugins add their own variables. The Git plugin, for example, adds names for the commit being built, the branch and the repository address, typically GIT_COMMIT, GIT_BRANCH and GIT_URL. Multibranch Pipelines add BRANCH_NAME for the branch being built, and for pull requests they add names such as CHANGE_ID and CHANGE_TARGET. These let a Pipeline behave differently for a feature branch than for the main branch, or for a pull request than for a release.
Jenkins keeps a reference page listing the variables available on your installation. On your own server, the Pipeline Syntax help includes a Global Variables Reference, and a page named env-vars.html under the Jenkins address lists the built-in ones. Because plugins vary, the list on your own server is the one that counts.
The built-in variables are like the labels a courier company automatically sticks on every parcel: tracking number, sender, destination and date. You did not write them, yet they are always there, and every handler along the route reads them.
4How a Variable Reaches Your Step
A short look at the journey explains why scope and syntax matter so much.
A step often runs on an agent, a worker machine, while the Pipeline is managed by the controller, the brain of Jenkins. When a step starts, Jenkins gathers the variables that apply, places them in the surroundings of the step process, and then starts your command. The command reads them using the syntax of whatever language it uses.
flowchart TD
A["Operating system variables of the agent"] --> M["Jenkins merges all layers"]
B["Global and node settings in Jenkins"] --> M
C["Built-in build variables"] --> M
D["Pipeline level and stage level definitions"] --> M
E["Parameters chosen for this build"] --> M
F["Bound credentials for a block"] --> M
M --> S["Environment placed around the step process"]
S --> R["Your command reads the values by name"]
The build starts
Jenkins creates a build and chooses an agent. The machine already has its own operating system variables.
Jenkins adds its layers
Global settings, machine settings, built-in build facts, plugin facts and parameters are added on top.
Your definitions are applied
Variables you defined in the job, the Pipeline, a stage or a block are added for the steps they cover.
The step process starts
Jenkins launches your shell or tool with the merged variables in its surroundings.
Your command reads by name
The shell, script or tool looks up each variable it needs, using its own syntax.
This is like preparing a kitchen station before a cook starts. Some tools are always there (operating system), the restaurant adds today’s specials (Jenkins layers), the head chef adds special instructions for one dish (your definitions), and only then does the cook begin, reading from all those notes without asking again.
5Ways to Define Your Own Variables
You can create variables at several levels, from the whole server down to a single block of steps.
| Where you define it | Who can see it | Good for |
|---|---|---|
| Global setting in Jenkins | Every build on every machine | Values shared by everything, such as a company-wide server address |
| Node (agent) setting | Every build that runs on that machine | Machine-specific values, such as the location of a tool on that agent |
| Freestyle project settings | That project’s builds | Simple values for one job |
| Pipeline level environment section | Every stage and step of that Pipeline | Values used throughout one Pipeline |
| Stage level environment section | Only the steps in that stage | Values that matter only to one phase |
| A wrapper step for a block | Only the steps inside the block | Temporary changes for a few steps |
| Build parameters | That single build, chosen by the person or trigger | Values that differ for each run |
| Set during the build in a script | Later steps of the same build | Values computed while running |
Global and node-level variables
An administrator can define variables for the whole Jenkins server in the system settings, under an area for global properties. Each agent machine can also carry its own variables in its configuration. Global values are shared by every build. Node values apply only to builds that land on that machine, which is handy when the same tool sits in different folders on different agents.
Freestyle projects
In a Freestyle project, the Build Environment section and parameter settings are the main places. Ticking “This project is parameterized” turns each parameter into an environment variable for the build. Some plugins add options in the Build Environment section for injecting more variables from a file or a list. Use such injection plugins with care and read their security notes, because they can widen who is able to affect a build’s surroundings.
Declarative Pipelines
In a Declarative Pipeline, you use a section named environment. Placed at the top level, it makes the variables available to every stage. Placed inside a stage, it makes them available only to that stage. Each entry is a name and a value, in the form NAME = 'value', and later entries can even use earlier ones. This is the tidiest and most popular way to define variables for a Pipeline.
Wrapper steps and scripts
The withEnv step is a wrapper. It takes a list of name and value pairs and applies them only to the steps inside its block. When the block ends, the variables vanish. In scripted code, you can also assign to the special env object, for example env.RELEASE_TYPE = 'beta', and later steps of the same build will see that value. This is useful when a value is calculated during the build.
Beware of assigning to variables inside script blocks and expecting every parallel branch to agree. If several branches write to the same variable at once, the result depends on timing. Give each branch its own clearly named value.
These levels are like notices in a school. A notice on the main gate is read by everyone (global). A notice on one classroom door is read only by that class (stage). A sticker on one student’s desk applies only while they sit there (wrapper block). The closer the notice is to you, the more specifically it applies.
6Scope and Which Value Wins
When the same name is defined in more than one place, Jenkins needs a rule for choosing.
Scope means the area in which a variable is visible. A stage-level variable is visible only inside its stage. A Pipeline-level one is visible everywhere in that Pipeline. A wrapper block gives visibility only inside the block.
The general principle is that the closest definition wins. If a Pipeline defines a variable and one stage defines the same name differently, the steps in that stage see the stage’s value, while the other stages still see the Pipeline’s value. A wrapper block placed inside a stage overrides both, for its steps only.
flowchart TD
G["Global or node value: REGION is eu"] --> P["Pipeline level: REGION is us"]
P --> S1["Stage Build: no override, sees us"]
P --> S2["Stage Deploy: sets REGION to ap"]
S2 --> W["Inside a wrapper block: REGION is set to sa"]
W --> V1["Steps inside the block see sa"]
S2 --> V2["Other Deploy steps see ap"]
S1 --> V3["Build steps see us"]
| Situation | What the step sees |
|---|---|
| Only a Pipeline-level value exists | That value, in every stage |
| Pipeline-level and stage-level values differ | The stage value inside that stage, the Pipeline value elsewhere |
| A wrapper block sets the name too | The block value inside the block only |
| A parameter and an environment entry share a name | Avoid this. Behaviour is easy to misjudge, so use distinct names |
| A variable defined only inside a stage is read in a later stage | Nothing. It is out of scope there |
| A variable is assigned in a script through the env object | The new value in later steps of the same build |
Do not rely on remembering subtle precedence rules across many layers. Choose unique, descriptive names for each variable, such as DEPLOY_REGION rather than REGION, and avoid defining the same name at several levels. Clear names beat clever knowledge.
7Reading Variables: Syntax Differences
The same variable is read in different ways, depending on where the reading happens. This is the single biggest source of beginner confusion.
| Where you read it | How you write the reading | Example for the build number |
|---|---|---|
| Inside a shell step on Linux or macOS | A dollar sign before the name | $BUILD_NUMBER |
| Inside a batch step on Windows | Percent signs around the name | %BUILD_NUMBER% |
| Inside a PowerShell step | A dollar sign and the word env with a colon | $env:BUILD_NUMBER |
| In Pipeline code, the Groovy language | The env object with a dot | env.BUILD_NUMBER |
| Inside a double-quoted Pipeline text | A dollar sign, filled in by Jenkins before the command starts | "Build ${env.BUILD_NUMBER}" |
| Inside a single-quoted Pipeline text | Left untouched. The shell fills it in later | 'echo $BUILD_NUMBER' |
Who fills in the value: Jenkins or the shell?
This detail deserves a slow explanation. In Pipeline files, text in double quotes is processed by Jenkins first: any ${...} placeholders are replaced with values before the command is even sent to the machine. Text in single quotes is passed exactly as written, and the shell on the machine fills in variables when the command runs. Both work for ordinary values, but they behave differently, and the difference matters greatly for secrets, as we will see next.
sequenceDiagram
participant P as Pipeline code
participant J as Jenkins engine
participant SH as Shell on the agent
Note over P,SH: Double quotes
P->>J: Text with a placeholder in double quotes
J->>J: Replace the placeholder with the value
J->>SH: Send the finished command with the value inside
Note over P,SH: Single quotes
P->>J: Text with a variable in single quotes
J->>SH: Send the command exactly as written
SH->>SH: Look up the variable in its own environment
A safe default: use single quotes for shell commands so the shell reads variables from its environment. Use double quotes only when Jenkins itself needs to build a piece of text, such as a message or a file name, from a value that is not secret.
Double quotes are like a secretary who fills in the blanks on a form before handing it to the worker. Single quotes are like handing over the form with blanks still empty, so the worker looks up the answers personally. If the answer is a secret, you would rather the worker fetch it from the locked cabinet than have it written on the form in advance.
8Environment Variables and Secrets
Variables are a convenient way to hand secrets to a step, but only if it is done through the right door.
A secret is a value that must not be seen by everyone: a password, a token or a private key. Jenkins keeps secrets in its credentials store, a protected vault. A plain environment variable is not a vault. Anyone who can read the Pipeline file or the console output can read it. So secrets must come from the credentials store, and be bound into a variable only for the moment they are needed.
The credentials helper in an environment section
A Declarative Pipeline can bind a stored credential to a variable name. For a username and password pair, Jenkins creates extra variables for the user and the password parts. Jenkins masks these values in the log.
The withCredentials wrapper
Binds a credential to a variable only inside a block, so the secret exists for the shortest possible time. Best for secrets needed by only one or two steps.
Credentials binding in Freestyle
A Build Environment option that binds stored credentials to variables for the build.
flowchart LR
V["Credentials store: protected vault"] -->|bind for a block| E["Environment variable exists only during the block"]
E --> S["Step reads the variable from its environment"]
S --> M["Jenkins masks the value if it appears in the log"]
E -->|block ends| X["Variable disappears"]
Masking, and its limits
When a secret is bound through the credentials system, Jenkins remembers its value and replaces it with stars if it shows up in the console output. This is a valuable safety net, but it is not perfect. A secret that is changed, encoded, split into pieces or embedded in a longer text may slip through unmasked. And secrets that Jenkins never knew were secrets, such as a password typed directly into a script or a plain variable, are not masked at all.
Using double quotes around a secret variable in a Pipeline makes Jenkins substitute the actual value into the command text itself, before the command runs. Jenkins warns about this because the value can then leak into logs, process lists and error messages. Use single quotes so that the shell reads the secret from its environment instead.
Habits that keep secrets safe
- Never type secrets into environment sections or scripts. Reference the credentials store instead.
- Bind as narrowly as possible. Use a wrapper block around only the steps that need the secret.
- Never print all variables. A command that lists the whole environment can reveal secrets that were not masked.
- Turn off command echoing near secrets. Shell steps normally print each command, so keep secret handling in scripts that do not echo them.
- Assume anything in a log is visible to your whole team. Logs are stored, shipped and pasted into chats.
- Rotate anything that leaks. Replace the secret immediately.
Binding a secret is like borrowing a key from a locked cabinet. You sign it out, use it for one task, and hand it back straight away. You never copy the key, stick it on the whiteboard, or shout its number across the room.
9Environment Variables, Parameters and Credentials Compared
Three ideas are often confused. Knowing the difference tells you which one to pick.
| Idea | Who supplies the value | When it is decided | Best for |
|---|---|---|---|
| Environment variable | The Pipeline author, an administrator or Jenkins itself | When the job is written or configured | Fixed settings, shared constants, build facts |
| Parameter | The person or trigger starting the build | At the moment the build starts | Choices that differ from run to run, such as a version or a target |
| Credential | The credentials store, managed by administrators | Stored beforehand, bound when needed | Secrets such as passwords, tokens and keys |
flowchart TD
N["I need a value in my build"] --> Q1{"Is it secret?"}
Q1 -->|Yes| C["Use the credentials store and bind it"]
Q1 -->|No| Q2{"Does it change with each run?"}
Q2 -->|Yes| P["Use a build parameter"]
Q2 -->|No| Q3{"Is it shared by many jobs?"}
Q3 -->|Yes| G["Use a global or node level variable"]
Q3 -->|No| E["Use a Pipeline or stage environment section"]
A parameter is like a question Jenkins asks before the build starts, such as “Which version should I build?” Once answered, its value is also made available as an environment variable, so your shell steps can read it by name, and Pipeline code can read it through the params object. So parameters and environment variables work together: parameters are one way that values arrive, and environment variables are one way they are read.
An order form at a restaurant shows the difference. The printed menu prices are fixed (environment variables). The choices the customer ticks, such as size and toppings, differ per order (parameters). The card payment details go into a secure terminal, not onto the paper (credentials).
10Passing Values Between Stages and Steps
Variables can carry information from one part of a build to another, but you must use the right method.
Sometimes a step discovers a fact that later steps need, such as a version number read from a file, or the name of a newly created resource. There are two common ways to pass it on.
Assign to the env object
In a script block, set a new value on the special env object. Later steps of the same build, in any stage, can read it. Good for computed values.
Capture command output
Ask a command step to return the text it printed, then store that text in a variable. Useful for reading versions and paths.
Two limits are worth knowing. First, a variable set by a shell command using the shell’s own syntax lives only inside that one shell process. When the step ends, the process ends, and the value is gone. The next step starts a fresh shell that knows nothing about it. This surprises nearly everyone at first. To keep a value, hand it back to Jenkins as a return value, then place it on the env object.
Second, the variables set inside a withEnv block or a stage environment section do not survive beyond their scope. Design each stage so that it does not depend on hidden leftovers from an earlier one.
sequenceDiagram
participant S1 as Step 1 shell process
participant J as Jenkins env object
participant S2 as Step 2 shell process
S1->>S1: Set a variable using shell syntax
Note over S1: Value exists only inside this process
S1-->>J: Process ends, the value is lost
J->>S2: Start a new shell with the Jenkins environment
S2->>S2: The shell variable from step 1 is not there
Note over J,S2: To keep a value, return it to Jenkins and store it on the env object
If a later stage needs a value, treat it as data to hand over deliberately. Return it from the step that found it, store it on the env object, and read it in the later stage. Deliberate hand-overs are easy to follow and debug.
A shell process is like a temporary workbench that is cleared away when the job ends. Anything you scribbled on it disappears. To keep a note for the next worker, you must pin it to the shared board, which in Jenkins is the env object.
11Variables Across Agents, Containers and Parallel Branches
The place where a step runs changes what it sees. This matters more as your setup grows.
Different agents, different surroundings
Each agent has its own operating system variables. A tool folder that exists on one machine may be missing from another, and the search path may differ. Variables from Jenkins itself, such as the build number, are the same everywhere, but machine facts differ. This is why a build can work on one agent and fail on another: a variable the step relied on is set differently on each.
Containers
When a step runs inside a container, the container has its own separate environment. Jenkins passes along some of its build variables, but the container’s own variables come from its image and settings. Treat a container as a fresh room: anything the tools inside need must be provided explicitly. In return, containers give you a big benefit, because every run starts from exactly the same surroundings.
Parallel branches
When stages run in parallel, each branch may run on a different agent, with its own surroundings. Variables defined at the Pipeline level are visible to all of them. But values assigned during the build by one branch are not a safe way to pass information to another branch, because their timing is unpredictable. Give each branch its own variables, and gather results at the end.
| Situation | What can go wrong | Safer approach |
|---|---|---|
| Different agents | Tool locations or search paths differ | Set tool variables per node, or use containers for identical surroundings |
| Inside containers | Expected variables are missing inside the container | Pass needed variables explicitly and keep images consistent |
| Parallel branches | Branches overwrite each other’s shared values | Use branch-specific names and collect results after the branches finish |
| Long Pipelines | Many overlapping definitions confuse readers | Define once at the top, and keep stage-level overrides rare |
Never assume the agent’s operating system variables are the same on every machine. If your step depends on a tool location or a version, either set it deliberately in the Pipeline or verify it at the start of the build, so failures explain themselves.
12Advantages, Disadvantages and Trade-offs
Environment variables are simple and useful, and they come with a few costs.
Advantages
- Very simple: a name and a text value.
- Supported by every language and tool.
- One place to change a value used in many steps.
- Jenkins supplies many useful facts for free.
- Works at global, machine, job, stage and block levels.
- Makes scripts portable between laptops and Jenkins.
Disadvantages and costs
- Values are text only, so numbers and lists need conversion.
- Too many layers make it hard to know which value applies.
- Plain variables are visible in files and logs, so they are unsafe for secrets.
- Quoting rules are subtle and easy to get wrong.
- Values do not travel across shell steps by themselves.
- Machine-specific values can cause “works on one agent” bugs.
The main trade-off is convenience versus clarity. Variables make a Pipeline flexible, but every extra layer makes it harder to see what a step will actually receive. Aim for a small number of well-named variables, defined in as few places as possible.
13Troubleshooting Common Problems
Most variable problems are of the same few kinds. Recognise the symptom, and the fix is usually short.
| Symptom | Likely cause | What to try |
|---|---|---|
| The variable prints as empty | It is not defined in that scope, or the name is misspelled | Check the spelling and capital letters, and check that the definition covers this step |
| The variable prints as the literal name, with a dollar sign | Wrong syntax for where it is read, for example shell syntax used in Pipeline code | Use the syntax that matches the place: shell, batch or Pipeline code |
| Works in one stage, missing in the next | The value was set in a stage-level section or a shell process, and went out of scope | Define it at the Pipeline level, or store it on the env object |
| Works on one agent but not another | Different operating system variables or tool locations | Print relevant variables, and set the values explicitly in the job |
| Windows step sees nothing | Shell syntax used in a batch step | Use percent signs, or the PowerShell form |
| A secret appears in the log | It was not bound through credentials, or it was transformed before printing | Bind properly, use single quotes, and rotate the leaked secret |
| A value has a stray newline or space | Captured command output includes trailing whitespace | Trim the captured text before storing it |
| A number does not compare correctly | All variable values are text | Convert to a number before doing arithmetic or comparisons |
| A variable seems to have two different values | The same name is defined at several levels | Rename to unique names, and remove duplicate definitions |
Print only what you need
Print the single variable in question, not the whole environment, to avoid exposing secrets.
Check the syntax for the place
Shell, batch, PowerShell and Pipeline code each read variables differently.
Check the scope
Is the step inside the stage, block or Pipeline where the variable was defined?
Check the machine
Which agent ran the step, and does it differ from a machine where it worked?
Compare with a good build
Open the console output of a working build and compare the values it shows.
The classic beginner trap is printing the entire environment “just to see everything”. Anything not properly masked, including tokens that were passed as plain variables, ends up in the log. Print only the specific variable you are investigating.
14Design Patterns and Anti-patterns
A pattern is a proven habit. An anti-pattern is a tempting shortcut that causes trouble later.
Patterns worth copying
Define once at the top
Declare shared values in one environment section at the start of the Pipeline, so readers see all settings in one place.
Descriptive names
Use names such as DEPLOY_TARGET or ARTIFACT_VERSION, in capital letters with underscores, so purpose is obvious.
Secrets only from the vault
Bind credentials for the smallest block, and never type secret values into files.
Parameters for per-run choices
Use parameters for values a person chooses at build time, and environment sections for fixed values.
Validate early
Check at the start that required variables exist and look sensible, and fail with a clear message if not.
Thin steps, script reads variables
Let scripts in your repository read their settings from variables, so they run the same on a laptop and in Jenkins.
Anti-patterns to avoid
What people do
They put passwords and tokens directly into an environment section or a global variable.
Why it hurts
Anyone who can read the Jenkinsfile, the job configuration or the logs can read the secret, and copies spread it further.
Better approach
Store the secret in the credentials store and bind it only where needed.
What people do
They print the whole environment on every build for convenience.
Why it hurts
Logs fill with noise and any unmasked secret is exposed to everyone who can read them.
Better approach
Print only the specific variables you need, and only while investigating.
What people do
They define the same name at global, node, Pipeline and stage levels.
Why it hurts
Nobody can tell which value a step will get, and a change in one place has surprising effects elsewhere.
Better approach
Use unique names and define each variable in exactly one place.
What people do
They rely on hidden machine settings, such as a variable that exists only on one agent.
Why it hurts
Builds pass on one agent and fail on another, and new agents must be tuned by hand.
Better approach
Set required values explicitly in the job, or use containers so surroundings are identical everywhere.
15Best Practices and Common Mistakes
A few steady habits keep your variables tidy, predictable and safe.
Best practices
- Use clear, unique names. Capital letters with underscores are the common convention.
- Define each variable in one place. Avoid the same name at several levels.
- Keep secrets in the credentials store. Bind them narrowly and mask them.
- Prefer single quotes for shell commands. Let the shell read variables from its environment.
- Use parameters for run-time choices. Use environment sections for fixed settings.
- Validate required values early. Fail with a friendly message rather than a mysterious error later.
- Document each variable. A short comment explains purpose and expected format.
- Remember values are text. Convert before comparing or calculating.
- Print selectively. Never dump the whole environment into a log.
- Keep the Jenkinsfile in version control. Changes to variables are then reviewed like any other change.
Common mistakes
Using the wrong reading syntax for the place. A dollar sign works in a Linux shell step but not in a Windows batch step, and Pipeline code uses the env object. Match the syntax to the place.
Expecting a shell step’s variable to survive to the next step. Each shell step is a separate process. Return the value to Jenkins and store it deliberately.
Trusting a value without checking. A missing variable often appears as an empty string, and a command with an empty value may do something dangerous, such as removing the wrong folder. Validate before using it in destructive commands.
Building file paths by hand instead of using the workspace variable. Hard-coded paths break when the job runs on a different agent or a different folder. Start from the workspace variable.
16Real-World Usage Patterns
Here is how teams use environment variables in everyday delivery work.
Naming and tagging builds
A team names every package and container image with the build number and the short commit fingerprint, both read from built-in variables. Any file found later can be traced straight back to the exact build and code that made it.
One Pipeline, three environments
A single Pipeline deploys to test, staging and production. A parameter chooses the target, and small lookup values, held as variables, supply the right server address for each. The steps are identical, and only the values differ, which keeps environments consistent.
Branch-aware behaviour
Using the branch name variable, a multibranch Pipeline runs quick checks on feature branches, full tests on the main branch, and a deployment only for release branches. One file serves every branch, and behaviour follows the branch.
Machine-specific tool locations
An organisation keeps tools in different folders on Linux and Windows agents. Each agent defines a variable holding its own tool folder, and jobs read that variable, so the same Pipeline works on both without change.
Safe cloud deployment
A deployment step needs a cloud access key. The team stores it in the credentials store and binds it for only that step. The key lives as a variable for seconds, is masked in the log, and never appears in the repository.
Notification messages
A failure message sent to team chat includes the job name, build number and build address, all read from built-in variables. Anyone reading the message can click straight through to the failing build.
17Frequently Asked Questions
18Summary and Key Takeaways
Environment variables are the shared whiteboard of a Jenkins build: labelled pieces of text that any step can read by name. Jenkins fills the board with useful facts, such as the build number, the workspace and the branch, and lets you add your own at the level of the server, the machine, the job, the stage or a single block of steps.
Using them well comes down to a few clear habits. Choose unique, descriptive names and define each one in a single place. Remember that values are text, that scope decides visibility, and that the closest definition wins. Use the right syntax for the place where you read the value, and prefer single quotes in shell commands. Keep secrets in the credentials store and bind them narrowly. With those habits, variables make your Pipelines flexible, portable and safe.
Key Takeaways
- An environment variable is a named text value that steps can read, and Jenkins provides many for free, such as build number, job name, workspace, node name and, with plugins, commit and branch.
- Define your own at the right level: global or node settings, a Freestyle project, a Pipeline or stage environment section, a withEnv block, or the env object in a script.
- Scope decides visibility, and the closest definition wins. Use unique names and define each variable in one place to avoid confusion.
- Syntax depends on where you read it: dollar sign in a Linux shell, percent signs in a Windows batch step, and the env object in Pipeline code.
- Prefer single quotes for shell commands, so the shell reads values from its environment rather than Jenkins pasting them into the command text.
- Keep secrets in the credentials store, bind them for the smallest block, never print the whole environment, and rotate anything that leaks.
- Values do not travel between shell steps by themselves. Return a value to Jenkins and store it on the env object to keep it, and remember that all values are text.