Jenkins Tool Management Architecture: ToolInstallation, ToolDescriptor, and DownloadFromUrlInstaller Explained

Jenkins tool management relies on an extensible descriptor-based architecture where ToolInstallation models a tool instance, ToolDescriptor registers it in the UI, and DownloadFromUrlInstaller handles automatic remote archive downloads.

Jenkins automates the provisioning of build tools across distributed agents through a flexible, plugin-extensible framework. The architecture centers on the ToolInstallation and ToolDescriptor classes, paired with installer implementations such as DownloadFromUrlInstaller, to let administrators declare, configure, and auto-install everything from JDKs to custom binaries. Understanding these core classes—as implemented in the jenkinsci/jenkins repository—reveals how Jenkins resolves tool locations at runtime and keeps agents consistently provisioned.

Core Components of the Jenkins Tool Management Architecture

ToolInstallation

ToolInstallation in core/src/main/java/hudson/tools/ToolInstallation.java represents a concrete installation of a tool, storing its name, home directory, and optional properties. It implements both Describable<ToolInstallation> and ExtensionPoint, which allows every tool type to expose its own ToolDescriptor. The class provides node-specific resolution through translate(Node, EnvVars, TaskListener) and preferredLocation, and it stores a list of ToolProperty objects—most notably InstallSourceProperty.

ToolDescriptor

ToolDescriptor<T extends ToolInstallation>, defined in core/src/main/java/hudson/tools/ToolDescriptor.java, acts as the descriptor for a concrete ToolInstallation subclass. It supplies UI metadata such as the display name and manages the list of configured installations via getInstallations(). Jenkins uses this descriptor to render the Tool Configuration page, and you can obtain registered descriptors through ToolInstallation.all().

InstallSourceProperty

InstallSourceProperty, found in core/src/main/java/hudson/tools/InstallSourceProperty.java, is a ToolProperty that bundles one or more installers for a tool. It holds a DescribableList<ToolInstaller, ...> that the UI renders as Auto-install options. When attached to a ToolInstallation, each installer receives the owning tool reference through installer.setTool(t).

ToolInstaller

ToolInstaller in core/src/main/java/hudson/tools/ToolInstaller.java performs the actual installation of a tool on a node. Its abstract performInstallation method receives the target ToolInstallation, the node, and a logger. Each installer carries a label expression that restricts which agents it may run on through appliesTo, and implementations are discovered via ToolInstallerDescriptor.all().

ToolInstallerDescriptor

ToolInstallerDescriptor<T extends ToolInstaller>, located in core/src/main/java/hudson/tools/ToolInstallerDescriptor.java, is the descriptor for a ToolInstaller. It determines whether an installer is applicable to a given ToolInstallation type through isApplicable(Class<? extends ToolInstallation>), which defaults to true. It also supplies UI helpers for label auto-completion and validation.

DownloadFromUrlInstaller

DownloadFromUrlInstaller in core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java is a concrete installer that downloads an archive from a URL and extracts it. It extends ToolInstaller and is configured with an ID that maps to an entry in the Jenkins update center JSON via the nested Installable class. It implements isUpToDate by checking a hidden .installedFrom marker file, and its performInstallation method downloads the archive, extracts it, optionally flattens a top-level directory, and writes the marker. The nested DescriptorImpl registers a Downloadable object so the update center can populate the list of available installables.

How the Jenkins Tool Management Architecture Works

The framework follows a clear lifecycle from definition to execution.

  1. Definition — A plugin or core module declares a concrete subclass of ToolInstallation. Its companion descriptor, extending ToolDescriptor, registers the installation type with Jenkins.

  2. Configuration — In the Global Tool Configuration UI, an administrator creates an instance of that installation, providing a name and home path. Optionally, an InstallSourceProperty is added, exposing one or more installers.

  3. Installer selection — The UI populates a drop-down with installers discovered through ToolInstallerDescriptor.for_(MyToolInstallation.class). For many core tools, the default choice is a subclass of DownloadFromUrlInstaller.

  4. Execution — When a build runs on a node, Jenkins calls ToolInstallation.translateFor(node, log). This method first checks ToolLocationNodeProperty for node-specific overrides. It then iterates over InstallSourceProperty.installers, invoking any installer whose appliesTo(node) returns true. The installer's performInstallation method lazily provisions the tool only when isUpToDate indicates it is needed.

  5. Result — The resolved FilePath for the tool's home directory on that node is returned, which subsequent build steps reference directly.

Implementing a Custom Tool with DownloadFromUrlInstaller

The following snippets show how to wire a custom tool into the Jenkins tool management architecture. The first block defines the tool and its descriptor; the second shows a custom URL-based installer.

// 1. Define a new ToolInstallation subclass
public class MyToolInstallation extends ToolInstallation
        implements NodeSpecific<MyToolInstallation>, EnvironmentSpecific<MyToolInstallation> {

    @DataBoundConstructor
    public MyToolInstallation(String name, String home, List<? extends ToolProperty<?>> properties) {
        super(name, home, properties);
    }

    @Override public MyToolInstallation forNode(Node node, TaskListener listener)
            throws IOException, InterruptedException {
        return (MyToolInstallation) translateFor(node, listener);
    }

    @Override public MyToolInstallation forEnvironment(EnvVars env) {
        return this; // no env-specific changes
    }
}

// 2. Provide a descriptor so Jenkins knows about the tool
@Extension
public static class DescriptorImpl extends ToolDescriptor<MyToolInstallation> {
    @Override public String getDisplayName() { return "My Custom Tool"; }
}
public class MyToolInstaller extends DownloadFromUrlInstaller {
    @DataBoundConstructor
    public MyToolInstaller(@CheckForNull String id) {
        super(id);   // id must match an entry in the update-center JSON
    }

    @Extension
    public static final class DescriptorImpl extends DownloadFromUrlInstaller.DescriptorImpl<MyToolInstaller> {}
}

When a user selects MyToolInstaller for My Custom Tool, Jenkins performs the following actions according to the jenkinsci/jenkins source code:

  • Loads the installable list from the update center using Downloadable.get(getId()).
  • Selects the entry whose id matches the installer's configured id.
  • Calls performInstallation to download and extract the archive onto the target node, verifying the .installedFrom marker to avoid redundant installs.

Summary

  • ToolInstallation defines a named tool instance and its properties, and translates itself for specific nodes.
  • ToolDescriptor registers the tool type with Jenkins and drives the configuration UI.
  • InstallSourceProperty groups one or more ToolInstaller instances under a single tool definition.
  • ToolInstaller and ToolInstallerDescriptor handle the actual provisioning logic and applicability checks.
  • DownloadFromUrlInstaller provides a ready-made implementation for fetching and extracting remote archives, keyed by update-center metadata.
  • The architecture resolves tool locations at runtime through translateFor, respecting node overrides and lazy-installing binaries only when needed.

Frequently Asked Questions

What is the role of ToolInstallation in Jenkins?

ToolInstallation is the base class that models a specific tool instance, storing its name, home directory, and properties such as InstallSourceProperty. It implements Describable<ToolInstallation> so that each concrete tool type can expose its own ToolDescriptor, and it provides methods like translateFor to resolve node-specific paths at runtime.

How does Jenkins decide which installer to use for a tool?

Jenkins discovers available installers through ToolInstallerDescriptor.all() and filters them by applicability using isApplicable(Class<? extends ToolInstallation>). When a build requires the tool on a node, InstallSourceProperty iterates over its configured installers and invokes the first one whose appliesTo check matches the node's labels.

What does DownloadFromUrlInstaller do under the hood?

DownloadFromUrlInstaller fetches an archive from a URL defined in the update-center JSON and extracts it on the target node. It writes a hidden .installedFrom marker file to track provenance, and its isUpToDate method skips reinstallation if the marker matches the current ID. The installer optionally pulls up a single top-level directory after extraction.

Can a tool have both a manual home path and an automatic installer?

Yes. A ToolInstallation always has a home path, but when you attach an InstallSourceProperty containing installers, Jenkins can disregard or supplement that path. At runtime, translateFor evaluates node overrides first, then installers, returning the resolved FilePath that the build step ultimately uses.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →