A minimal script is a single .java file with a typical static void main method or a .jsh file which will be passed to jshell.

Below is an (almost) minimal example you can save in or simply run jbang init

///usr/bin/env jbang "$0" "$@" ; exit $? (1)

class helloworld { (2)

    public static void main(String[] args) {
        if(args.length==0) {
            System.out.println("Hello World!");
        } else {
            System.out.println("Hello " + args[0]);
1 By using this // style instead of shebang #! you trick bash, zsh etc. to run this as a script while still being valid java code.
2 A classname, can be anything when using jbang but to be valid java for most IDEs you’ll want to name it the same as the source file.

Now to run this you can call it via jbang:


or if on Linux/OSX/AIX run it directly. If you created it manually you need to mark it as executable before running it.

chmod +x
./ jbang!

If you are using another shell than bash or zsh, like Fish shell be aware that such shell limits the syntax in top line to start with !# thus it won’t be as transparent. Here you will need to run using jbang directly, i.e. jbang jbang!.

When no JDK version is available in the PATH, JDK 11 will be downloaded by default to bootstrap jbang. If your script requires a higher version and you don' want to download two JDK’s, you can define an alternative default with JBANG_DEFAULT_JAVA_VERSION env variable.


Note that if JDK is found in the PATH, JBANG_DEFAULT_JAVA_VERSION will be ignored.

Default application

If you pass a directory or a url ending in / jbang will look for to run as default application for that directory / location.

URLs from Trusted Sources

You can use http(s):/ and file:/ url’s for input:.


For safety reasons jbang will not run arbitrary urls before you indicated you trust their source. Thus when running the above for the first time you will see the following warning about the url not being a trusted source:

[jbang] is not from a trusted source thus not running it automatically.

If you trust the url to be safe to run you can do one of the following:
0) Trust once: Add no trust, just run this time
1) Trust this url in future:
    jbang trust add

Any other response will result in exit.

[jbang] Type in your choice (0 or 1) and hit enter. Times out after 10 seconds.

You can then choose 0 to run once or 1 to trust the suggested url. If you don’t answer within 10 seconds jbang will exit.

To enable running it without such question you need to mark that url or a sub part of it as a trusted source. i.e. jbang trust add will tell jbang to trust anything with that base url.

You can see more in the comments of the ~/.jbang/trusted-sources.json.

Sites such as GitHub, gitlab, bitbucket, gist, jbang will try and extract the proper source rather than the raw html. i.e. doing jbang carbon! is possible.

URL’s will follow redirects. In case you need to use it with sites with self-signed/non-trusted certificates you can if you trust the site use --insecure.

Build and run native image (Experimental)

There is support for using native-image from GraalVM project to produce a binary executable.

Since not all java libraries can automatically be built with native-image - especially if using reflection feature are considered highly experimental.

Just run jbang --native and jbang will use native-image from either $JAVA_HOME/bin or $GRAALVM_HOME/bin or $PATH to produce a native image binary.

If you want to have a copy of the generated binary you can run jbang export local -n

You can install the native-image utility binary e.g. by installing GraalVM from, and then once running gu install native-image as per

If you use --native with picocli remember to add info.picocli:picocli-codegen as that will ensure it will actually work with native-image.

Using .jsh for jshell

There is support to run .jsh via jshell. The advantage of jshell is that you do not need to have a class or static main method.

Classic jshell does not support passing in arguments nor system properties, jbang does.

In the case of .jsh files jbang injects a startup script that declares a String[] args which will contain any passed in arguments, and it sets any properties passed in as -Dkey=value as parameters to jbang.

That means you can run a script as jbang -Dkey=value helloworld.jsh World and retrieve arguments and properties as:

System.out.println("Hello " + (args.length>0?args[0]:"World")); (1)
System.out.println(System.getProperty("key")); (2)
1 Line where args are accessible without previous declaration.
2 System properties set when passed as -D arguments to jbang

The script will have the output:

Hello World

Please note that .jsh files are source only, they are not compiled thus they are not cached nor can they be built as native images.

If you use -Dkey where no value is specified jbang will interpret this as -Dkey=true allowing you to easily have flags passed into, i.e. jbang -DskipTests Now within your script `Boolean.getBoolean('skipTests') will return true.

Running Kotlin (.kt) (EXPERIMENTAL)

As an experiment since 0.71.0 JBang supports building Kotlin files using kotlinc.

jbang init -t hello.kt hello.kt
[jbang] Downloading Kotlin 1.5.0. Be patient, this can take several minutes...
[jbang] Installing Kotlin 1.5.0...
[jbang] Building jar...
Hello World

Running script from standard input

jbang can run scripts directly from standard input using - or /dev/stdin as input.

i.e. then you can "pipe" the script to jbang:

echo 'System.out.println("Hello World!");' | jbang -

jbang will try and guess if the piped content is a java class and if not assume it it is jshell code. To force jbang to run it as a jshell script you can use --jsh flag.

If you use --interactive jbang will let jshell enter into interactive/REPL mode. You can write /exit to leave this mode. If you are after running .java code via piping or curl it is better to use jbang’s support for running http(s) urls directly, i.e. jbang <urlto-java>.

If your own code needs to handle chained pipes well it is recommended to add the following code:

import sun.misc.Signal;

if (!"Windows".equals(System.getProperty(""))) {
    Signal.handle(new Signal("PIPE"), (final Signal sig) -> System.exit(1));

It will give a compiler warning as it is internal API; but for now it works.

Running .jar's

jbang will also run .jar files directly.

i.e. jbang helloworld.jar will run helloworld.jar if found on your local file system.

The .jar can be a local file or a http/https url.

You can also run a .jar file referenced by a Maven coordinate, i.e.:

jbang info.picocli:picocli-codegen:4.5.0

This will fetch the dependency stated and put the transitive dependencies on the class-path.

If you need to specify a main class you can do so by using --main i.e.

jbang --main picocli.codegen.aot.graalvm.ReflectionConfigGenerator info.picocli:picocli-codegen:4.5.0

A side effect of running GAV as a jar, the GAV could also be a .java or .jsh file and it would be launched as a script instead of a jar. No one would want to do that (right?) but now you know.

Usage on Windows

Some JBang commands need to create symbolic links when running on Windows. For example, this is required for Managing JDKs or editing the files with the edit command. To resolve the issue, on Windows 10 you will need to enable symbolic linking for your user account.

  • Review security considerations and best practices here.

  • Enable the Create symbolic links group policy setting for your user/group by following the guidelines on the User Rights Assignment page.

You might also need elevated privileges to create symbolic links If the JBang process has no full administrative rights, the execution may result in an error like:

java.nio.file.FileSystemException: <CURRENT_JDK>: A required privilege is not held by the client.

To resolve this issue, see the options in this article. There are multiple possible resolutions, choose one meeting your needs.

For older Windows versions, see this StackOverflow issue.