# How Jenkins Manages Workspace Allocation Across Agents: A Deep Dive into WorkspaceList

> Learn how Jenkins manages workspace allocation across agents. Discover its thread-safe WorkspaceList and lease-based directory locking for concurrent builds. Optimize your CI/CD.

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

---

**Jenkins isolates workspace allocation per agent using a thread-safe `WorkspaceList` that tracks directory locks through a lease-based system with automatic suffix generation (`@2`, `@3`, etc.) for concurrent builds.**

When multiple builds run concurrently on the same agent, Jenkins must prevent directory collisions while allowing parallel execution. The jenkinsci/jenkins repository implements this through a sophisticated **workspace allocation** mechanism centered on the `WorkspaceList` class, which provides thread-safe reservation and per-agent isolation across the entire Jenkins environment.

## The WorkspaceList Architecture

### Per-Agent Workspace Isolation

Each Jenkins agent (represented by the `Computer` class) maintains its own `WorkspaceList` instance. This design guarantees that allocation decisions on one agent never interfere with another, even when jobs share identical names across different nodes.

Jenkins accesses these registries through two primary entry points:

- **`Computer#getWorkspaceList()`** – Returns the `WorkspaceList` associated with that specific agent.
- **`Jenkins#getWorkspaceFor(Job)`** – Convenience method that resolves the proper `Computer` for a job (considering assigned labels) and delegates to that agent's `WorkspaceList`.

### The Allocation Algorithm

The core logic resides in `WorkspaceList.allocate(FilePath base, Object context)` inside [`core/src/main/java/hudson/slaves/WorkspaceList.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/slaves/WorkspaceList.java). The algorithm executes the following steps:

1. **Base path determination** – The job defines a base directory (typically `<agent-root>/workspace/<job-name>`).
2. **Uniqueness iteration** – The method iterates through suffixes `@2`, `@3`, and so on until finding a candidate directory that is either not locked or held by an entry sharing the same **context** (enabling parallel pipeline stages to reuse workspaces).
3. **Entry creation** – Creates an `Entry` object stored in the internal `inUse` map, recording:
   - The owning thread (`holder`)
   - Allocation timestamp (`time`)
   - Stack trace for debugging (`source`)
   - Context object for re-entrancy
4. **Lease return** – Returns a `WorkspaceList.Lease` implementing `AutoCloseable`. When the build finishes, the lease's `release()` method decrements the lock count and removes the entry from `inUse`.

## Workspace Allocation Mechanisms

### Normal vs. Quick Allocation

Jenkins supports two distinct allocation modes:

**Normal allocation** – The default path used by `allocate(base, context)`. When the primary workspace is occupied, the allocator automatically adds numeric suffixes (`@2`, `@3`) until locating a free directory.

**Quick allocation** – Invoked via `allocate(p, true, context)` or `acquire(base, true)`, this mode blocks other normal allocations from using that path until the quick lease releases. This mode suits short-lived operations (like sanity checks) that must not interfere with concurrent long-running builds.

### Temporary Directory Handling

The `WorkspaceList.tempDir(FilePath ws)` method creates a sibling directory using the `TMP_DIR_SUFFIX` constant (`@tmp`). This provides transient storage for caches and intermediate files that persist across builds reusing the same workspace, but disappear when the workspace itself is cleaned.

## Implementation Examples

### Pipeline Usage (Declarative)

Standard pipeline syntax automatically handles workspace allocation through the `node` step:

```groovy
node('my-agent') {
    def ws = pwd()  // Returns allocated path like /var/jenkins/workspace/my-job@2
    echo "Allocated workspace: ${ws}"
    sh "echo 'Building...' > build.log"
    // Workspace automatically released when node block exits
}

```

### Direct WorkspaceList Access (Advanced Plugins)

Plugins requiring explicit control can interact with the `WorkspaceList` directly:

```java
import hudson.FilePath;
import hudson.model.Computer;
import hudson.slaves.WorkspaceList;
import hudson.slaves.WorkspaceList.Lease;

Computer computer = // ... obtain target agent
WorkspaceList wsList = computer.getWorkspaceList();
FilePath base = new FilePath(computer.getRootPath(), "workspace/my-job");

// Context allows re-entrancy for parallel pipeline stages
Object context = build;

try (Lease lease = wsList.allocate(base, context)) {
    FilePath ws = lease.path;
    // Perform build steps
    ws.child("result.txt").write("Completed", "UTF-8");
}
// Lease automatically releases here via AutoCloseable

```

### Quick Allocation for Short-Lived Tasks

Use quick allocation when you need exclusive access without generating new suffixed directories:

```java
try (Lease quickLease = wsList.acquire(base, true)) {
    // Blocks other allocations; ideal for fast consistency checks
    performSanityCheck(quickLease.path);
}

```

### Accessing Temporary Directories

Retrieve the associated temporary directory for cache storage:

```java
FilePath tmp = WorkspaceList.tempDir(ws);
if (tmp != null) {
    tmp.mkdirs();
    // Store transient cache data
    tmp.child("maven-cache").mkdirs();
}

```

## Key Source Files

The workspace allocation system spans these critical files in the jenkinsci/jenkins repository:

- [`core/src/main/java/hudson/slaves/WorkspaceList.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/slaves/WorkspaceList.java) – Core implementation of the allocation algorithm, lease management, and temporary directory handling.
- [`core/src/main/java/hudson/model/Computer.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/model/Computer.java) – Agent representation that owns the `WorkspaceList` instance and provides `getWorkspaceList()`.
- [`core/src/main/java/jenkins/model/Jenkins.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/jenkins/model/Jenkins.java) – Master-level coordination via `getWorkspaceFor(Job)`.
- [`core/src/main/java/hudson/model/AbstractProject.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/model/AbstractProject.java) – Integration point for Freestyle and Pipeline jobs.
- [`core/src/main/java/hudson/model/Run.java`](https://github.com/jenkinsci/jenkins/blob/main/core/src/main/java/hudson/model/Run.java) – Build-level workspace storage via `Run#getWorkspace()`.

## Summary

- Each Jenkins agent maintains an isolated **`WorkspaceList`** that prevents cross-agent workspace collisions.
- The **allocation algorithm** automatically appends numeric suffixes (`@2`, `@3`) to accommodate concurrent builds of the same job.
- **Lease objects** implement `AutoCloseable` to ensure thread-safe lock release when builds complete.
- **Quick allocation** provides exclusive short-term access without creating new directory suffixes.
- **Temporary directories** (`@tmp` siblings) persist across builds but clean with the workspace.

## Frequently Asked Questions

### How does Jenkins prevent workspace conflicts when multiple builds run concurrently?

Jenkins uses the `WorkspaceList` class on each agent to track occupied directories. When a build requests a workspace, the `allocate()` method checks the internal `inUse` map and automatically generates unique directory names by appending `@2`, `@3`, etc., until finding an available path. Each allocation returns a `Lease` that locks the directory until the build releases it.

### Can parallel pipeline stages share the same workspace?

Yes, parallel stages within the same pipeline can share a workspace if they pass the same **context object** (typically the `Run` instance) to the `allocate()` method. When the context matches an existing entry, Jenkins increments the lock count rather than creating a new suffixed directory, allowing true parallel execution within identical workspace paths.

### What is the difference between normal and quick workspace allocation?

**Normal allocation** recursively searches for the next available suffixed directory when the primary workspace is occupied. **Quick allocation**, invoked with `acquire(base, true)` or `allocate(path, true, context)`, blocks other normal allocations from using that specific path until the lease releases, making it ideal for short-lived operations that must not interfere with long-running builds.

### Where does Jenkins store temporary files associated with a workspace?

Jenkins creates a sibling directory using the `TMP_DIR_SUFFIX` constant (set to `@tmp`) via `WorkspaceList.tempDir(FilePath ws)`. This temporary directory survives across multiple builds that reuse the same workspace but is removed when the workspace itself is cleaned, providing a transient storage location for caches and intermediate files.