# How Jenkins Build Wrappers Modify the Build Execution Environment: A Complete Guide

> Learn how Jenkins build wrappers modify your build execution environment. Discover how they inject variables, decorate output, and manage cleanup through this comprehensive guide.

- Repository: [Jenkins/jenkins](https://github.com/jenkinsci/jenkins)
- Tags: deep-dive
- Published: 2026-06-19

---

**Jenkins build wrappers modify the build execution environment by intercepting the launcher, injecting environment variables, decorating console output, and registering cleanup disposers through the `BuildWrapper` and `SimpleBuildWrapper` extension points.**

In the **jenkinsci/jenkins** repository, **Build Wrappers** serve as extension points that allow plugins to set up and tear down services around a build execution. These wrappers influence how jobs run by modifying the launcher, environment variables, and logging behavior before and after the main build steps execute.

## Understanding the BuildWrapper Extension Point

The core abstraction resides in [`hudson/tasks/BuildWrapper.java`](https://github.com/jenkinsci/jenkins/blob/main/hudson/tasks/BuildWrapper.java). This class defines multiple hooks that execute at different phases of the build lifecycle, allowing fine-grained control over the execution environment. According to the Jenkins source code, a wrapper operates by returning an `Environment` object from its `setUp` method, which persists throughout the build and manages resource cleanup.

## Core Mechanisms for Environment Modification

### Workspace Setup and Teardown Hooks

The primary entry point for modifying the build environment is `setUp(Context, Run, FilePath, Launcher, TaskListener, EnvVars)`. As documented in [`BuildWrapper.java`](https://github.com/jenkinsci/jenkins/blob/main/BuildWrapper.java) (lines 31-52, 71-89), this method returns a `BuildWrapper.Environment` object that persists for the duration of the build. The default implementation allows plugins to register a **Disposer**—a cleanup callback that executes after the build step finishes, ensuring resources are released regardless of build success.

### Environment Variable Injection

The inner class `BuildWrapper.Environment` extends `hudson.model.Environment` and provides the `buildEnvVars(Map<String,String>)` method. As implemented in [`SimpleBuildWrapper.java`](https://github.com/jenkinsci/jenkins/blob/main/SimpleBuildWrapper.java) (lines 16-23), this method is called before each build step, allowing the wrapper to merge variables defined in the Context into the build's live environment.

### Launcher Decoration

The `decorateLauncher` hook runs before the `setUp` phase, giving wrappers the chance to wrap the `Launcher` instance. The default implementation in [`BuildWrapper.java`](https://github.com/jenkinsci/jenkins/blob/main/BuildWrapper.java) (lines 81-89) is a no-op, but plugins may return a custom `LauncherDecorator` to prepend commands like *sudo* or adjust the execution environment before commands are launched.

### Console Log Filtering

The `decorateLogger` method allows wrappers to provide a `ConsoleLogFilter` that transforms console output before it is written to the log. This is demonstrated in [`SimpleBuildWrapper.java`](https://github.com/jenkinsci/jenkins/blob/main/SimpleBuildWrapper.java) (lines 42-47) and tested in [`SimpleBuildWrapperTest.java`](https://github.com/jenkinsci/jenkins/blob/main/SimpleBuildWrapperTest.java), enabling plugins to mask sensitive data or format output.

### Pre-Checkout Execution

The `preCheckout` method, defined in [`BuildWrapper.java`](https://github.com/jenkinsci/jenkins/blob/main/BuildWrapper.java) (lines 140-152), invokes the wrapper early—before SCM checkout occurs. This enables workspace preparation or cleanup actions that must happen prior to source code retrieval, such as deleting leftover files from previous builds.

## Modern Implementation with SimpleBuildWrapper

The `SimpleBuildWrapper` class in [`jenkins/tasks/SimpleBuildWrapper.java`](https://github.com/jenkinsci/jenkins/blob/main/jenkins/tasks/SimpleBuildWrapper.java) provides a streamlined API that abstracts the traditional hooks into a **Context**-based pattern, reducing boilerplate while maintaining full control over the execution environment.

### The Context Object Pattern

The `Context` object collects environment variable overrides and stores them for later injection. The `setUp` method creates this context and returns an `EnvironmentWrapper`:

```java
@Override
public final Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) {
    Context ctx = createContext();
    setUp(ctx, build, build.getWorkspace(), launcher, listener, build.getEnvironment(listener));
    return new EnvironmentWrapper(ctx, launcher);
}

```

The `Context.env(String key, String value)` method stores overrides such as `PATH+STUFF` (see [`SimpleBuildWrapper.java`](https://github.com/jenkinsci/jenkins/blob/main/SimpleBuildWrapper.java), lines 72-78). During the build, the `EnvironmentWrapper.buildEnvVars` method (lines 16-22) merges these stored variables into the build's `EnvVars`, making them available to all subsequent build steps.

### Disposer Pattern for Cleanup

Wrappers register cleanup logic through `Context.setDisposer(Disposer d)`. The `Disposer`'s `tearDown` method executes after the build step completes (lines 24-28), ensuring resources are properly released regardless of build success or failure:

```java
ctx.setDisposer(new Disposer() {
    @Override
    public void tearDown(Run<?,?> build, FilePath workspace, Launcher launcher, 
                        TaskListener listener) throws IOException, InterruptedException {
        listener.getLogger().println("Cleaning up wrapper resources...");
        // Cleanup logic executes post-build
    }
});

```

## Practical Implementation Examples

The Jenkins test suite in [`test/src/test/java/jenkins/tasks/SimpleBuildWrapperTest.java`](https://github.com/jenkinsci/jenkins/blob/main/test/src/test/java/jenkins/tasks/SimpleBuildWrapperTest.java) demonstrates common patterns for modifying the execution environment.

**Modifying PATH Environment Variables**

Wrappers can prepend to PATH using the `PATH+KEY` syntax, which appends the value to the existing PATH variable:

```java
// Adds PATH+STUFF pointing to a bin directory inside the workspace
ctx.env("PATH+STUFF", workspace.child("bin").getRemote());

```

**Variable Expansion and Ordering**

References like `${HOME}` are expanded when building new variables, allowing complex environment construction:

```java
ctx.env("EXTRA", "${HOME}/tools");
ctx.env("PATH+EXTRA", "${EXTRA}/bin");

```

**Console Output Transformation**

Implement `decorateLogger` to return a `ConsoleLogFilter` that transforms log output:

```java
@Override
public ConsoleLogFilter createLoggerDecorator(Run<?,?> build) {
    return new ConsoleLogFilter() {
        @Override
        public OutputStream decorateLogger(Run build, OutputStream logger) {
            return new UpperCaseOutputStream(logger);
        }
    };
}

```

## Summary

- **BuildWrapper** in [`hudson/tasks/BuildWrapper.java`](https://github.com/jenkinsci/jenkins/blob/main/hudson/tasks/BuildWrapper.java) provides the core extension point for modifying build execution through setup, teardown, and decoration hooks.
- The `setUp` method establishes the environment, while the inner `Environment` class handles variable injection and cleanup.
- **Launcher decoration** via `decorateLauncher` allows command interception and modification before execution.
- **Console log filtering** through `decorateLogger` enables real-time output transformation.
- **SimpleBuildWrapper** offers a modern **Context**-based API with the **Disposer** pattern for simplified resource management.
- The `preCheckout` hook runs before SCM checkout, enabling early workspace preparation.

## Frequently Asked Questions

### What is the difference between BuildWrapper and SimpleBuildWrapper?

**SimpleBuildWrapper** is a modern convenience class that extends BuildWrapper and abstracts the complex lifecycle hooks into a simpler Context-based API. While BuildWrapper requires manual implementation of Environment classes and teardown logic, SimpleBuildWrapper handles these through the Context object and Disposer pattern, reducing boilerplate code while maintaining the same capabilities.

### When does a BuildWrapper's setUp method execute relative to SCM checkout?

By default, `setUp` runs after SCM checkout. However, if the wrapper overrides `runPreCheckout()` to return `true`, Jenkins invokes `preCheckout` instead, which executes before the SCM checkout phase. This is defined in [`BuildWrapper.java`](https://github.com/jenkinsci/jenkins/blob/main/BuildWrapper.java) (lines 140-152), allowing wrappers to clean or prepare the workspace before source code retrieval.

### How do Jenkins build wrappers handle sensitive environment variables?

Wrappers override `makeSensitiveBuildVariables` to return a `Set<String>` of variable names that should be masked in the console output. Combined with `makeBuildVariables`, this allows wrappers to inject credentials or secrets while preventing them from appearing in build logs, as the sensitive marker informs Jenkins' log masking infrastructure.

### Can multiple build wrappers modify the same build environment?

Yes, Jenkins executes multiple wrappers in sequence. Each wrapper's environment modifications layer on top of previous ones. The `EnvironmentWrapper` class in SimpleBuildWrapper merges variables incrementally, allowing cumulative changes to the launcher, environment variables, and logger without conflicts between different wrapper implementations.