Well, that’s not entirely accurate – for years, despite being a “Java guy,” I actually wrote all my utility scripts in Python or Bash. And the idea of spinning up a Maven project, configuring a pom.xml, and setting up the directory structure just to parse a CSV file or call a REST API felt like trying to kill a mosquito with a bazooka. It was overkill. It hurt.

But that changed for me recently. I finally forced myself to sit down and properly integrate JBang into my daily workflow. If you haven’t looked at this tool since it was just a niche experiment, you are missing out. It’s not just a “nice to have” anymore; as of early 2026, it is legitimately the bridge that makes Java viable for scripting. And seeing it get prime slots at conferences like Devoxx just confirms I’m not the only one tired of context-switching languages just to move some files around.

The Problem with “Just Running Java”

Let’s be real. Java has historically been terrible at being small. You want to use a library? Great, download the JAR, add it to the classpath, or—more likely—spend twenty minutes fighting with Gradle. By the time you’re done setting up, you could have written the script in Python three times over.

JBang bypasses all that nonsense. It lets you run .java files as scripts. No build file. No boilerplate. Just code. JBang is an open-source tool that aims to make Java more accessible for scripting and small-scale applications. The official JBang GitHub repository provides more information about the tool’s features and usage.

I tested this out on my M3 MacBook (running macOS 15.2) last Tuesday when I needed to quickly scrape some JSON data from a staging endpoint. Usually, I’d reach for curl and jq, but the logic was getting complex. I decided to try JBang with Java 25. The experience was… disturbingly smooth.

How It Actually Works

The magic isn’t just running the file; it’s how it handles dependencies. You declare them right in the file using a comment header. JBang fetches them, builds the classpath, and runs the main method. It feels illegal.

Here is the script I wrote. Note the //DEPS line. That is literally all the configuration you need to pull in Jackson for JSON processing.

///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS com.fasterxml.jackson.core:jackson-databind:2.18.2

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.JsonNode;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class StatusChecker {

    public static void main(String... args) {
        var url = "https://api.github.com/zen";
        
        try {
            System.out.println("⏳ Checking GitHub Zen...");
            
            var client = HttpClient.newHttpClient();
            var request = HttpRequest.newBuilder()
                    .uri(URI.create(url))
                    .GET()
                    .build();

            var response = client.send(request, HttpResponse.BodyHandlers.ofString());
            
            if (response.statusCode() == 200) {
                System.out.println("✅ Success! The wisdom is:");
                System.out.println("   \"" + response.body() + "\"");
            } else {
                System.err.println("❌ Failed with status: " + response.statusCode());
            }
            
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}

You save that as StatusChecker.java, make it executable with chmod +x, and run it with ./StatusChecker.java. That’s it. JBang downloads Jackson 2.18.2 (or whatever version you specify), caches it, and executes.

Why This Beats Python for Me

Look, I like Python. But I don’t like managing venv, pip, and Python versions across three different servers. With JBang, the dependency definition lives inside the script. If I send this file to my colleague running Ubuntu 24.04, it just works. They don’t need to pip install anything. JBang handles the environment.

I ran a quick benchmark just to see if the startup time was painful. On a cold run (downloading dependencies), it took about 4 seconds. But on subsequent runs? 0.35 seconds. For a JVM startup, that is negligible for my use case. The JBang performance documentation provides more details on startup times and caching behavior.

The CLI Superpower: Picocli

Where JBang really shines is when you combine it with Picocli to make robust command-line tools. I used to dread parsing args[] manually. “Did the user pass -f or --file? Did they provide a value?” It’s tedious logic to write from scratch.

JBang has a shorthand for this. You can generate a CLI template instantly. Here is a stripped-down version of a tool I built to clean up old log files. It uses the //DEPS magic to pull in Picocli, making the argument parsing declarative.

///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS info.picocli:picocli:4.7.6

import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;

import java.io.File;
import java.util.concurrent.Callable;

@Command(name = "cleaner", mixinStandardHelpOptions = true, version = "cleaner 1.0",
         description = "Cleans up files older than X days.")
class LogCleaner implements Callable<Integer> {

    @Parameters(index = "0", description = "The directory to clean")
    private File directory;

    @Option(names = {"-d", "--days"}, description = "Age in days (default: 30)")
    private int days = 30;

    @Override
    public Integer call() throws Exception {
        if (!directory.exists() || !directory.isDirectory()) {
            System.err.println("❌ Error: Directory does not exist.");
            return 1;
        }

        System.out.printf("🧹 Scanning %s for files older than %d days...%n", 
                          directory.getAbsolutePath(), days);
        
        // Mock logic for demonstration
        long count = 0; 
        // Imagine complex file IO logic here
        
        System.out.println("✅ Scan complete. Found " + count + " files to remove.");
        return 0;
    }

    public static void main(String... args) {
        int exitCode = new CommandLine(new LogCleaner()).execute(args);
        System.exit(exitCode);
    }
}

Running ./LogCleaner.java --help automatically generates a beautiful help message. I didn’t have to write a single line of help text logic. Picocli is a popular Java command-line parsing library that provides a declarative approach to building CLI applications. The Picocli website has more information about its features and usage.

A Warning for New Adopters

It’s not all sunshine. I did run into a snag last month when trying to use JBang with a very specific, older version of a private corporate library hosted on our internal Nexus. The authentication setup for JBang to talk to private Maven repositories can be a bit finicky compared to a standard Maven settings.xml setup.

But I eventually solved it by exporting the JBANG_REPO environment variable. If you are working in a locked-down enterprise environment, expect to spend an hour configuring your proxies and auth tokens the first time you set it up. The JBang configuration documentation provides guidance on setting up private repository access.

Why This Matters Now

We are seeing tools like JBang get stage time at major events because the Java ecosystem is finally acknowledging that developer experience matters. For too long, we accepted that Java was “heavy” and “enterprise.” Tools like this prove that Java can be nimble.

Related Post