Learn Jenkins - Variables, Environment & Secret Management
Episode 5 of 21

Learn Jenkins - Variables, Environment & Secret Management

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.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

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.

Main Discussion

Built-in Environment Variables

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:

VariableContents
BUILD_NUMBERSequential build number, e.g. 42
JOB_NAMEJob name, e.g. my-app
GIT_COMMITHash of the commit being built
WORKSPACEAbsolute path of the agent workspace
JOB_URLFull job URL
BUILD_URLFull build URL
NODE_NAMEName 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:

JenkinsReading Jenkins built-in variables
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.

Defining Custom Variables

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:

JenkinsCustom environment variables
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 Jenkins Credentials Provider

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:

TypeUse
Secret textAPI keys, tokens, passwords only
Secret fileCredential files such as kubeconfig or JSON keys
Username with passwordUser + password combinations (e.g. registry login)
SSH Username with private keyFor 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.

Retrieving Credentials with withCredentials

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.

Fetch a secret text with withCredentials
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:

Fetch a username and password for docker login
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.

Caution: Never Print Secrets

Storing secrets properly is only half the battle; the other half is not leaking them into logs. Non-negotiable rules:

  1. Never echo a secret value into the Console Output — not even "just for debugging".
  2. Never paste a secret as a command-line argument visible in the log (e.g. curl -u user:pass ... in literal form).
  3. Never turn a secret into a global variable that can be printed from another stage.
  4. When running commands that use secrets, use environment variables ($API_KEY), not string literals.
The right way vs the wrong way to use secrets
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.

Conclusion

In episode 5 you have understood:

  • Jenkins built-in variables — BUILD_NUMBER, JOB_NAME, GIT_COMMIT, WORKSPACE and others — accessed via env.BUILD_NUMBER in Groovy or $BUILD_NUMBER in the shell.
  • Custom variables with the environment { APP_NAME = 'my-app' } block.
  • The Jenkins Credentials Provider: secret text, secret file, username+password, and SSH private keys, all referenced by credentialsId.
  • Retrieving credentials securely with the 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!