How To Install Gradle on Ubuntu 26.04 LTS

Install Gradle on Ubuntu 26.04

Every few years a new Ubuntu LTS drops, and every few years the same question pops up in DevOps Slack channels and support tickets: “why does gradle -v throw a Java error right after a fresh install?” If you’ve just spun up Ubuntu 26.04 LTS and you’re staring at a build pipeline that refuses to cooperate, you’re not alone, and you’re in the right place.

Gradle isn’t just another build tool you apt install and forget about. It’s the backbone of most modern Java, Kotlin, and Android build pipelines, and how you install it on a server determines whether your CI/CD jobs run smoothly six months from now or whether you’ll be debugging classpath conflicts at 2 AM during a release freeze. On Ubuntu 26.04 LTS specifically, there’s a bit of nuance worth understanding — the default APT repositories rarely ship the latest Gradle release, JDK version compatibility has shifted again, and the way Canonical packages build tools has changed slightly across recent LTS cycles.

This guide walks through the installation from a production-first mindset. That means we’re not just running commands blindly — we’re talking about why the manual installation method is generally preferred over APT for build tools, how to properly configure environment variables so Gradle survives reboots and multi-user environments, and what to do when things go sideways (because they eventually will, usually right before a deadline).

Whether you’re setting up a single developer workstation, provisioning a CI runner, or hardening a shared build server that a dozen engineers hit simultaneously, the steps below apply. We’ll cover the manual ZIP installation (the recommended approach for anything beyond a throwaway VM), the SDKMAN route (handy for developers juggling multiple Gradle versions), verification steps, common errors pulled from real troubleshooting sessions, and the performance and security considerations that separate a “it works” setup from one that’s actually production-ready.

Why Gradle Installation Method Matters on Ubuntu 26.04 LTS

Before jumping into commands, it’s worth addressing something most tutorials skip entirely: the installation method you choose has downstream consequences.

Ubuntu’s official repositories package Gradle inconsistently across releases — sometimes it’s missing entirely, sometimes it lags several major versions behind upstream. Relying on apt install gradle on a fresh Ubuntu 26.04 LTS box will often hand you an outdated build, which becomes a real problem the moment your project’s build.gradle or build.gradle.kts file demands a feature from Gradle 8.x or 9.x that the packaged version simply doesn’t support. On a personal laptop that’s an annoyance. On a shared CI server building dozens of microservices, it’s a pipeline-breaking incident.

That’s why the manual binary distribution method (downloading directly from Gradle’s servers and extracting to /opt) remains the gold standard in production environments. It gives you exact version control, predictable upgrade paths, and no dependency on Canonical’s packaging schedule.

Prerequisites Before You Start

Gradle runs on the JVM, so nothing works without a properly configured Java environment first. Skipping this step — or getting it wrong — is the single most common cause of installation headaches.

  • A fresh or updated Ubuntu 26.04 LTS system with sudo privileges
  • At least 2GB of free disk space (Gradle caches grow fast, especially with Android or multi-module projects)
  • A stable internet connection for downloading the distribution archive
  • curl or wget, plus unzip (rarely preinstalled on minimal server images)
  • A supported JDK — Gradle 8.5+ requires JDK 17 minimum, and Gradle 9.x runs best on JDK 21 LTS

Run a quick update first. It sounds obvious, but skipping it on a freshly provisioned VM is where half of “mysterious” installation errors originate.

sudo apt update && sudo apt upgrade -y

Step 1: Install a Compatible JDK

Ubuntu 26.04 LTS ships OpenJDK packages in its default repos, and installing the headless variant is the smart move for servers — you don’t need a graphical Java runtime on a build box.

sudo apt install --no-install-recommends openjdk-21-jdk-headless -y

Verify the installation immediately:

java -version

You should see output referencing OpenJDK 21. If your project specifically targets an older Gradle version tied to JDK 17, install that instead:

sudo apt install --no-install-recommends openjdk-17-jdk-headless -y

A quick note from experience: on multi-JDK boxes (common on shared CI runners where different projects need different Java versions), use update-alternatives --config java to manage the active version explicitly rather than letting APT pick one arbitrarily. This avoids the classic scenario where a build works fine locally but fails on the runner because it silently picked up JDK 11 from some legacy dependency.

sudo update-alternatives --config java

Step 2: Download the Gradle Binary Distribution

Head over to Gradle’s official releases and grab the latest stable version number, or check directly via the download endpoint. As of this writing, Gradle 8.x and 9.x branches are both actively maintained, so pick based on your project’s build.gradle requirements.

Set the version as a variable — this makes future upgrades trivial and avoids typos in long URLs:

GRADLE_VERSION=8.10.2
curl -L --fail -o /tmp/gradle-${GRADLE_VERSION}-bin.zip \
  https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip

The --fail flag matters more than it looks. Without it, curl will happily save an HTML error page as your zip file if the URL is wrong, and you won’t notice until unzip throws a cryptic “not a zip file” error five minutes later.

Step 3: Verify the Download (Don’t Skip This)

This is the step most tutorials conveniently omit, and it’s exactly the kind of shortcut that comes back to bite you on a production server. Gradle publishes SHA-256 checksums for every release specifically so you can confirm the binary wasn’t corrupted or tampered with in transit.

curl -L -o /tmp/gradle-${GRADLE_VERSION}-bin.zip.sha256 \
  https://gradle.org/release-checksums/

Compare manually against the published hash, or automate it in your provisioning scripts:

sha256sum /tmp/gradle-${GRADLE_VERSION}-bin.zip

For anything touching a CI/CD pipeline or a server with external network access, treat this as non-negotiable. Supply-chain attacks on build tools are a real and growing threat vector — a compromised build tool can inject malicious code into every artifact it produces.

Step 4: Extract Gradle to a System-Wide Location

Install unzip if it’s not already present:

sudo apt install unzip -y

Extract into /opt/gradle, which is the conventional Linux location for manually installed, self-contained software packages:

sudo mkdir -p /opt/gradle
sudo unzip -q /tmp/gradle-${GRADLE_VERSION}-bin.zip -d /opt/gradle

Create a symlink pointing to the currently active version. This one habit saves enormous pain later:

sudo ln -sfn /opt/gradle/gradle-${GRADLE_VERSION} /opt/gradle/latest

Why bother with the symlink instead of just adding the versioned path to PATH directly? Because when you eventually need to upgrade — and you will, Gradle ships new versions frequently — you just re-point the symlink instead of editing every environment file and CI configuration that references the old path. It’s a small thing, but it’s the difference between a five-second upgrade and an afternoon of hunting down hardcoded paths across your infrastructure.

Step 5: Configure Environment Variables

Add Gradle to the system-wide PATH so every user on the machine can access it without per-user configuration:

echo 'export PATH=$PATH:/opt/gradle/latest/bin' | sudo tee /etc/profile.d/gradle.sh
sudo chmod +x /etc/profile.d/gradle.sh

Load it into your current session without logging out:

source /etc/profile.d/gradle.sh

If you’re managing a single-user workstation instead of a shared server, adding the export line to ~/.bashrc or ~/.zshrc works just as well and keeps the configuration scoped to that user only.

Step 6: Verify the Installation

gradle -v

Expect output listing the Gradle version, build time, revision, and — critically — the JVM version it’s running on. If the JVM line shows a version you didn’t expect, that’s your first clue something’s misconfigured in JAVA_HOME or your alternatives setup.

Run a quick smoke test in an isolated directory:

mkdir -p ~/gradle-test && cd ~/gradle-test
gradle init --type basic
gradle tasks

If both commands complete without errors, the installation is functionally sound.

Alternative Method: Installing via SDKMAN

For developer workstations where multiple Gradle versions might need to coexist across different projects, SDKMAN is genuinely the better tool. It’s less suited to hardened production servers (it adds shell hooks and a management layer you may not want on a minimal CI image), but for local development it’s excellent.

curl -s "https://get.sdkman.io" | bash
source "$HOME/.sdkman/bin/sdkman-init.sh"
sdk install gradle 8.10.2

Switching between versions per-project becomes trivial:

sdk use gradle 7.6.4

This is particularly useful if you maintain legacy Android projects alongside newer Kotlin Multiplatform builds — each can pin its own Gradle version without conflict.

Using the Gradle Wrapper Instead (Recommended for Projects)

Here’s a practical insight from years of managing build infrastructure: for actual projects, you rarely want developers or CI runners depending on a system-wide Gradle install at all. The Gradle Wrapper (gradlew) bundles the exact required version with the project itself, eliminating “works on my machine” version drift entirely.

Once Gradle is installed system-wide (which you still need for the initial wrapper generation), run:

gradle wrapper --gradle-version 8.10.2

This generates gradlew, gradlew.bat, and a gradle/wrapper/gradle-wrapper.properties file. Commit all of these to version control. From that point forward, anyone cloning the repo runs ./gradlew build and gets the exact same Gradle version automatically downloaded and cached — no manual installation required on their end.

Troubleshooting Common Gradle Installation Errors

“gradle: command not found” After Installation

This almost always means the PATH export either wasn’t sourced or was written to the wrong profile file. Confirm the symlink exists and check which profile script your shell actually reads:

echo $SHELL
ls -la /opt/gradle/latest/bin/gradle
cat /etc/profile.d/gradle.sh

If you’re SSH’d in via a non-login shell (common with some automation tools), /etc/profile.d/ scripts may not load at all. In that case, source the script explicitly in your deployment scripts or add the export directly to .bashrc.

“Unsupported class file major version” Error

This is a JDK mismatch, plain and simple. Gradle was compiled against a specific bytecode version, and running it against a JDK it doesn’t support throws this exact error. Check both versions:

gradle -v
java -version

If there’s a mismatch, either upgrade your JDK or downgrade Gradle to a version compatible with your installed JDK. Gradle’s compatibility matrix on their official docs is worth bookmarking.

Permission Denied Errors During Extraction

Happens when /opt ownership doesn’t match expectations, especially on servers hardened with strict umask settings. Fix ownership explicitly rather than loosening permissions broadly:

sudo chown -R root:root /opt/gradle
sudo chmod -R 755 /opt/gradle

Gradle Daemon Hangs or Consumes Excessive Memory

Common on memory-constrained VMs or containers. The Gradle Daemon caches JVM state between builds to speed things up, but on a 1-2GB RAM instance, this backfires. Cap daemon memory explicitly in ~/.gradle/gradle.properties:

org.gradle.jvmargs=-Xmx1024m -XX:MaxMetaspaceSize=512m
org.gradle.daemon=true
org.gradle.parallel=true

Corporate Proxy or Firewall Blocking Downloads

If curl times out during the download step, your server likely sits behind a corporate proxy. Configure it explicitly before retrying:

export https_proxy=http://proxy.internal.company.com:8080
export http_proxy=http://proxy.internal.company.com:8080

This same environment variable needs setting inside gradle.properties for Gradle itself to route dependency downloads correctly, otherwise builds will hang indefinitely trying to reach Maven Central.

Performance Tuning for Production Build Servers

Once Gradle is installed and working, the next question on any decently sized build server is throughput — how do you keep builds fast when you’ve got dozens of jobs queued during a release crunch?

CPU and parallelism: Enable parallel project execution and configure worker count based on actual core count, not guesswork:

org.gradle.parallel=true
org.gradle.workers.max=4

Memory allocation: Undersized heap settings cause constant garbage collection pauses; oversized settings starve other processes on shared boxes. On a dedicated 8GB build server, something like -Xmx4096m leaves headroom for the OS and other services without starving Gradle.

Disk I/O: Gradle’s build cache and dependency cache live under ~/.gradle by default. On servers running many concurrent builds, moving this cache to fast NVMe storage (rather than network-attached storage) makes a measurable difference — dependency resolution and incremental build checks are I/O-heavy operations.

Build cache: Enable the local and, if available, remote build cache to avoid rebuilding unchanged modules:

org.gradle.caching=true

On a CI fleet with multiple runners, a shared remote build cache server can cut aggregate build time dramatically since one runner’s compiled output becomes reusable by others.

Network considerations: Point Gradle at a local Maven mirror or Nexus/Artifactory instance for dependency resolution rather than hitting Maven Central directly on every build. This alone often shaves seconds off every single build across a busy CI environment, and it insulates you from upstream repository outages.

Security Hardening Considerations

Build tools sit in a uniquely sensitive position — they execute arbitrary code (build scripts, plugins, annotation processors) with whatever permissions the running user has. A few practices matter more here than on typical application servers:

  • Never run Gradle builds as root, even on CI runners. Create a dedicated unprivileged build user.
  • Enable dependency verification (gradle-wrapper.properties checksum validation) on every project, not just the ones you consider “important.”
  • Restrict outbound firewall rules on build servers to only the repositories and mirrors your builds actually need — this limits blast radius if a compromised dependency tries to phone home.
  • Audit third-party Gradle plugins the same way you’d audit any dependency; a malicious or compromised plugin has build-time code execution, which is a far more dangerous position than a runtime library dependency.
  • Keep JDK versions patched. Java security vulnerabilities affecting the JVM directly impact anything Gradle compiles or runs.
  • Isolate CI build agents with containerization or VMs so a compromised build can’t pivot laterally into shared infrastructure.
r00t is a Linux Systems Administrator and open-source advocate with over ten years of hands-on experience in server infrastructure, system hardening, and performance tuning. Having worked across distributions such as Debian, Arch, RHEL, and Ubuntu, he brings real-world depth to every article published on this blog. r00t writes to bridge the gap between complex sysadmin concepts and practical, everyday application — whether you are configuring your first server or optimizing a production environment. Based in New York, US, he is a firm believer that knowledge, like open-source software, is best when shared freely.

Related Posts