Managing variables and secrets in Jenkins: built-in variables such as the build number and job name, custom variables, centralized credential storage, and securely retrieving secrets with the withCredentials wrapper.

The pipelines in episodes 2-4 are still plain: they print messages and can be triggered automatically, but they do not yet interact with real data — the build number, job name, the commit being built, or the secrets needed to access registries and servers. In episode 5, your pipelines will "talk". We will cover built-in environment variables, custom variables, and — most important for your career — secret management with Jenkins Credentials.
The last part deserves extra attention. The most fatal mistake in the Jenkins world is not bad syntax, but credentials leaking into the build log. After this episode, you will know exactly how to store, retrieve, and use secrets without ever writing them in the wrong place.
Every build automatically receives a set of environment variables from Jenkins. These are the "identity card" of the running build, and they are used very often in real pipelines:
| Variable | Contents |
|---|---|
BUILD_NUMBER | Sequential build number, e.g. 42 |
JOB_NAME | Job name, e.g. my-app |
GIT_COMMIT | Hash of the commit being built |
WORKSPACE | Absolute path of the agent workspace |
JOB_URL | Full job URL |
BUILD_URL | Full build URL |
NODE_NAME | Name of the agent executing the build |
How to access them in a pipeline: via the env object, e.g. env.BUILD_NUMBER (in Groovy), or directly as a shell variable $BUILD_NUMBER inside a sh block. Let's see both:
pipeline {
agent any
stages {
stage('Info') {
steps {
echo "Nomor build: ${env.BUILD_NUMBER}"
echo "Nama job: ${env.JOB_NAME}"
echo "Commit: ${env.GIT_COMMIT}"
}
}
}
}Note that the expression env.BUILD_NUMBER inside a string is simply Groovy string interpolation — the value is inserted into the string before echo runs. For use inside shell commands, use $BUILD_NUMBER, which is handled by the shell itself. These two mechanisms (Groovy interpolation vs shell expansion) often confuse beginners, so remember: in Groovy use env, in the shell use the dollar sign directly.
Note
Built-in variables are useful for artifact labeling — for example naming a Docker image with the build number, or naming test reports with the job name. This is a pattern you will encounter in almost every production pipeline.
Jenkins also provides the environment block for defining your own variables. Variables defined at the pipeline level apply to the entire pipeline; redefining them at the stage level makes them specific to that stage:
pipeline {
agent any
environment {
APP_NAME = 'my-app'
REGISTRY = 'registry.example.com'
}
stages {
stage('Print') {
steps {
echo "Aplikasi: ${env.APP_NAME}"
echo "Registry: ${env.REGISTRY}"
}
}
}
}They are accessed exactly like built-in variables: env.APP_NAME in Groovy or $APP_NAME in the shell. Use this block for values that are constant and non-sensitive — application version, project name, environment URL. For secret values, never put them here in plaintext; use the Credentials Provider below.
The Credentials Provider is the centralized credential store in Jenkins (Manage Jenkins → Credentials). It stores secrets in encrypted form and exposes them to pipelines only through an ID — so the Jenkinsfile never contains a secret value. The most common credential types:
| Type | Use |
|---|---|
| Secret text | API keys, tokens, passwords only |
| Secret file | Credential files such as kubeconfig or JSON keys |
| Username with password | User + password combinations (e.g. registry login) |
| SSH Username with private key | For SSH agents and deploying over SSH |
Each credential gets a unique credentialsId — this is what pipelines reference. The actual value is stored encrypted in JENKINS_HOME, and only Jenkins can decrypt it when needed.
To use credentials in a pipeline, use the withCredentials wrapper. This wrapper fetches the credential from the store, injects it as an environment variable only for the duration of the block, then cleans it up after the block finishes — and Jenkins automatically masks the value if it appears in the log.
withCredentials([string(credentialsId: 'api-key-prod', variable: 'API_KEY')]) {
sh 'curl -H "Authorization: Bearer $API_KEY" https://api.example.com/v1/data'
}Let's break it down: string(...) selects the credential type, credentialsId: 'api-key-prod' points to the credential in the store, and variable: 'API_KEY' defines the environment variable name. Inside the block, the shell command uses $API_KEY — the actual value never appears in the Jenkinsfile. The same pattern applies to other types:
withCredentials([usernamePassword(credentialsId: 'registry-login', usernameVariable: 'REG_USER', passwordVariable: 'REG_PASS')]) {
sh 'docker login -u "$REG_USER" -p "$REG_PASS" registry.example.com'
}Tip
Best practice: store all secrets in the Credentials Provider, reference them by credentialsId, and never write them in the Jenkinsfile or environment variables. If a secret needs to be rotated, just update it in the store — every job using it automatically changes without any code edits.
Storing secrets properly is only half the battle; the other half is not leaking them into logs. Non-negotiable rules:
echo a secret value into the Console Output — not even "just for debugging".curl -u user:pass ... in literal form).$API_KEY), not string literals.withCredentials([string(credentialsId: 'api-key', variable: 'TOKEN')]) {
sh 'curl -H "Authorization: $TOKEN" https://api.example.com'
echo "Token saya: ${env.TOKEN}"
}Note the last line: that is a wrong example that should not be copied — that line prints a secret into the log. The preceding sh line is safe because $TOKEN is expanded by the shell (the value is not written as a literal), and Jenkins masks its value in the log if it leaks. The only correct way to use a secret is through an environment variable inside withCredentials.
Warning
A secret leaking into a build log is a security incident — not just a style mistake. Build logs are usually kept for a long time and often copied into aggregation tools. If you ever suspect a secret has leaked, immediately revoke and rotate that credential in the Credentials Provider.
In episode 5 you have understood:
BUILD_NUMBER, JOB_NAME, GIT_COMMIT, WORKSPACE and others — accessed via env.BUILD_NUMBER in Groovy or $BUILD_NUMBER in the shell.environment { APP_NAME = 'my-app' } block.credentialsId.withCredentials wrapper, and the hard rule to never print secrets into logs.The key takeaway to carry with you: build data lives in environment variables, and secrets live in Credentials — not in the Jenkinsfile. In episode 6 we will combine everything you've learned into an interactive, secure pipeline: parameterized pipelines with input forms, manual approval gates for deployment, and timeout handling — the foundation for a controlled release flow. See you in episode 6!