Getting Started with GraalVM

Get started with GraalVM – a high-performance runtime that provides significant improvements in application performance and efficiency which is ideal for microservices. It is designed for applications written in Java and other JVM languages while also providing a high-performance runtime for JavaScript, Ruby, Python, and a number of other popular languages.

Here you will find information about installing GraalVM, running basic applications with it, and adding support for its accompanying features. Further, you will learn about polyglot capabilities of GraalVM and see how to build platform-specific native executables of JVM-based applications.

If you are new to GraaVM or have little experience using it, we recommened to start with Introduction to GraalVM page. There you will find information about GraalVM’s architecture, distributions available, supported platforms, core and additional features, and much more.

If you have GraalVM already installed and have experience using it, you can skip this getting started guide and proceed to in-depth Reference Manuals.

Install GraalVM #

Getting GraalVM installed and ready-to-go should only take a few minutes. Choose a platform and proceed to the installation steps:

Start Running Applications #

In this getting started guide we will focus on working with GraalVM Community Edition based on OpenJDK 8.

The core distribution of GraalVM includes the JVM, the GraalVM compiler, LLVM runtime, and Node.js JavaScript runtime. Having downloaded and installed GraalVM, you can already run Java, Node.js, JavaScript, and LLVM-based applications.

GraalVM’s /bin directory is similar to that of a standard JDK, but includes a set of additional launchers:

  • js a JavaScript launcher
  • node a Node.js launcher
  • lli a LLVM bitcode interpreter
  • gu the GraalVM Updater tool to install additional language runtimes and utilities

Check the versions of the runtimes provided by default:

java -version
java version "1.8.0_261"
Java(TM) SE Runtime Environment (build 1.8.0_261-b33)
Java HotSpot(TM) 64-Bit Server VM GraalVM EE 20.2.0-dev (build 25.261-b33-jvmci-20.2-b03, mixed mode)

node -v
v12.18.0

lli --version
LLVM (GraalVM EE Native 20.2.0)

The executables of all language runtimes in GraalVM emulate the behavior of the languages’ default runtimes. Further below you will find information on how to run other optionally available languges (Ruby, R, Python, and WebAssembly) with GraalVM.

Running Java #

The java launcher runs the JVM with the GraalVM default compiler - the GraalVM compiler. Take a look at this typical HelloWorld class:

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, World!");
  }
}

Run the following commands to compile this class to bytecode and then execute it:

javac HelloWorld.java
java HelloWorld
Hello World!

You can find a collection of larger Java examples on the Examples Applications page. For more extensive documentation on running Java applications, proceed to JVM Languages.

Running JavaScript and Node.js #

GraalVM can execute plain JavaScript code, both in REPL mode and by executing script files directly:

js
> 1 + 2
3

GraalVM also supports running Node.js applications. More than 100,000 npm packages are regularly tested and are compatible with GraalVM, including modules like express, react, async, request, browserify, grunt, mocha, and underscore. To install a Node.js module, use the npm executable from the /bin folder, provided by default. The npm command is equivalent to the default Node.js command and supports all Node.js APIs.

  1. Install the colors and ansispan modules using npm install. After the modules are installed, you can use them from your application.
    npm install colors ansispan
    
  2. Use the following code snippet and save it as the app.js file in the same directory where you installed the Node.js modules:
  // BEGIN-SNIPPET
const http = require("http");
const span = require("ansispan");
require("colors");

http.createServer(function (request, response) {
    response.writeHead(200, {"Content-Type": "text/html"});
    response.end(span("Hello Graal.js!".green));
}).listen(8000, function() { console.log("Graal.js server running at http://127.0.0.1:8000/".red); });

setTimeout(function() { console.log("DONE!"); process.exit(); }, 2000);
// END-SNIPPET

  
  1. Run app.js using GraalVM’s node command:
    node app.js
    

For more detailed documentation and information on compatibility with Node.js, proceed to JavaScript and Node.js.

Running LLVM Languages #

The GraalVM LLVM runtime can execute C/C++, Rust, and other programming language that can be compiled to LLVM bitcode. A native program has to be compiled to LLVM bitcode using an LLVM frontend such as clang. C/C++ code can be compiled to LLVM bitcode using clang shipped with GraalVM via a prebuilt LLVM toolchain.

To set up the LLVM toolchain support, execute the following commands:

$ gu install llvm-toolchain
$ export LLVM_TOOLCHAIN=$(lli --print-toolchain-path)

As an example, put this C code into a file named hello.c:

#include <stdio.h>

int main() {
    printf("Hello from GraalVM!\n");
    return 0;
}

Then compile hello.c to an executable hello with embedded LLVM bitcode and run it as follows:

$LLVM_TOOLCHAIN/clang hello.c -o hello
lli hello

For in-depth documentation and more examples of running LLVM bitcode on GraalVM, go to LLVM Languages .

Python #

With GraalVM you can run Python applications in the Python 3 runtime environment. The support is not available by default, but you can quickly add it to GraalVM using the GraalVM Updater tool:

gu install python

Once Python is installed, you can run Python programs:

graalpython
...
>>> 1 + 2
3
>>> exit()

More examples and additional information on Python support in GraalVM can be found in the Python reference manual.

Running Ruby #

GraalVM provides a high-performance Ruby runtime environment including the gem command that allows you to interact with RubyGems, Ruby Bundler, and much more. The Ruby runtime is not available by default in GraalVM, but can be easily added using the GraalVM Updater tool:

gu install ruby

The above command will install a community version of a component from GitHub catalog. Then Ruby launchers like ruby, gem, irb, rake, rdoc, and ri become available to run Ruby programs:

ruby [options] program.rb

GraalVM Ruby runtime environment uses the same options as the standard implementation of Ruby, with some additions. For example:

gem install chunky_png
ruby -r chunky_png -e "puts ChunkyPNG::Color.to_hex(ChunkyPNG::Color('mintcream @ 0.5'))"
#f5fffa80

More examples and in-depth documentation can be found in the Ruby reference manual.

Running R #

GraalVM provides a GNU-compatible environment to run R programs directly or in the REPL mode. Although, the R language support is not available by default, but you can add it to GraalVM using the GraalVM Updater tool:

gu install R

When the language is installed, you can execute R scripts and use the R REPL:

R
R version 3.6.1 (FastR)
...

> 1 + 1
[1] 2

More examples and in-depth documentation can be found in the R reference manual.

WebAssembly #

With GraalVM your can run WebAssembly programs. The support is not available default, but you can add it to GraalVM using the GraalVM Updater tool:

gu install wasm

Then the wasm launcher, that can run compiled WebAssembly binary code, becomes available.

As an example, assume the following C program has already been compiled:

#include <stdio.h>

int main() {
  int number = 1;
  int rows = 10;
  for (int i = 1; i <= rows; i++) {
    for (int j = 1; j <= i; j++) {
      printf("%d ", number);
      ++number;
    }
    printf(".\n");
  }
  return 0;
}

This is how you can run the compiled WebAssembly binary:

wasm --Builtins=memory,env:emscripten floyd.wasm

More details can be found in the WebAssembly reference manual.

Combine Languages #

GraalVM allows you to call one programming language into another and exchange data between them. To enable interoperability, GraalVM provides the --polyglot flag.

For example, running js --jvm --polyglot example.js executes example.js in a polyglot context. If the program calls any code in other supported languages, GraalVM executes that code in the same runtime as the example.js application. For more information on running polyglot applications, see Polyglot Programming.

Native Images #

With GraalVM you can compile Java bytecode into a platform-specific, self-contained, native executable - a native image - to achieve faster startup and a smaller footprint for your application. The Native Image functionality is not available by default, but can be easily installed with the GraalVM Updater tool:

gu install native-image

The HelloWorld example from above is used here to demonstrate how to generate a native image:

// HelloWorld.java
public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Hello, World!");
  }
}

Compile HelloWorld.java to bytecode and then build a native image:

javac HelloWorld.java
native-image HelloWorld

The last command generates an executable file named helloworld in the current working directory. Invoking it executes the natively compiled code of the HelloWorld class as follows:

./helloworld
Hello, World!

More detailed documentation on this innovative technology is available in the Native Image reference manual.

Polyglot Capabilities of Native Images #

GraalVM makes it possible to use polyglot capabilities when building native images. Take this example of a JSON pretty-printer Java program that embeds some JavaScript code:

// PrettyPrintJSON.java
import java.io.*;
import java.util.stream.*;
import org.graalvm.polyglot.*;

public class PrettyPrintJSON {
  public static void main(String[] args) throws java.io.IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    String input = reader.lines().collect(Collectors.joining(System.lineSeparator()));
    try (Context context = Context.create("js")) {
      Value parse = context.eval("js", "JSON.parse");
      Value stringify = context.eval("js", "JSON.stringify");
      Value result = stringify.execute(parse.execute(input), null, 2);
      System.out.println(result.asString());
    }
  }
}

Compile it and build a native image for it. The --language:js argument ensures that JavaScript is available in the generated image:

javac PrettyPrintJSON.java
native-image --language:js --initialize-at-build-time PrettyPrintJSON

The native image generatation will take several minutes as it does not just build the PrettyPrintJSON class, but also builds JavaScript. Additionally, the image building requires large amounts of physical memory, especially if you build an image with the Language Implementation Framework included, which is the case here.

The resulting executable can now perform JSON pretty-printing:

./prettyprintjson <<EOF
{"GraalVM":{"description":"Language Abstraction Platform","supports":["combining languages","embedding languages","creating native images"],"languages": ["Java","JavaScript","Node.js", "Python", "Ruby","R","LLVM"]}}
EOF

Here is the JSON output from the native executable:

{
  "GraalVM": {
    "description": "Language Abstraction Platform",
    "supports": [
      "combining languages",
      "embedding languages",
      "creating native images"
    ],
    "languages": [
      "Java",
      "JavaScript",
      "Node.js",
      "Python",
      "Ruby",
      "R",
      "LLVM"
    ]
  }
}

The native image runs much faster than running the same code on the JVM directly:

time bin/java PrettyPrintJSON < test.json > /dev/null
real	0m1.101s
user	0m2.471s
sys	0m0.237s

time ./prettyprintjson < test.json > /dev/null
real	0m0.037s
user	0m0.015s
sys	0m0.016s

GraalVM Community Container Images #

GraalVM Community container images are available for download from GitHub Packages.

As long as GitHub does not support anonymous access you need to login to the registry to authenticate against the GitHub Package server. You can authenticate to GitHub Packages with Docker using the docker login command. It is required to use a personal access token with the appropriate scopes for authentication. Learn how to generate personal access tokens here.

As a best practice, it is suggested to save your personal access token in a file locally. Then run the docker login command non-interactively so you can set the --password-stdin flag to provide a token. The following example shows how to read a token from a file and pass it to the docker login command using STDIN:

cat ~/TOKEN.txt | docker login https://docker.pkg.github.com -u USERNAME --password-stdin

Substitute USERNAME with your GitHub username and ~/TOKEN.txt with the file path to the file containing your personal access token. Once you have authenticated, there are two ways to install GraalVM Community container images published as GitHub Packages.

  1. Pull the image from GitHub with docker pull:
    docker pull docker.pkg.github.com/graalvm/container/community:latest
    
  2. Alternatively, use as the base image in Dockerfile:
    FROM docker.pkg.github.com/graalvm/container/community:latest
    

There are different GraalVM Community container images provided depending on the architecture and Java version. A complete list can be found on the All versions page. The images are named per a platform-os-jdk-version naming scheme, for example, docker.pkg.github.com/graalvm/container/community:ol8-java11-20.2.0. The images for 64-bit ARM architecture are prefixed with the arm64- tag, e.g., docker.pkg.github.com/graalvm/container/community:arm64-ol8-java11-20.2.0.

The container image is based on Oracle Linux and has GraalVM Community downloaded, unzipped and made available. It means that Java, JavaScript, Node and the LLVM interpreter are available out of the box.

You can start a container and enter the bash session with the following run command:

docker run -it docker.pkg.github.com/graalvm/container/community:20.2.0 bash

Check that java, js and other commands work as expected.

→ docker run -it docker.pkg.github.com/graalvm/container/community:20.2.0 bash
bash-4.4# java -version
openjdk version "11.0.8" 2020-07-14
OpenJDK Runtime Environment GraalVM CE 20.2.0 (build 11.0.8+10-jvmci-20.2-b03)
OpenJDK 64-Bit Server VM GraalVM CE 20.2.0 (build 11.0.8+10-jvmci-20.2-b03, mixed mode, sharing)
bash-4.4# node
Welcome to Node.js v12.18.0.
Type ".help" for more information.
> 1 + 1
2
> process.exit()
bash-4.4# lli --version
LLVM (GraalVM CE Native 20.2.0)
bash-4.4#

Please note that the image contains only the components immediately available in the GraalVM Community distribution. However, the GraalVM Updater utility is on the PATH. You can install the support for additional languages like Ruby, R, Python or WebAssembly at will. For example, the following command installs the Ruby support (the output below is truncated for brevity):

docker run -it docker.pkg.github.com/graalvm/container/community:20.2.0 bash
bash-4.4# gu install ruby
Downloading: Component catalog
Processing component archive: Component ruby
Downloading: Component ruby
[######              ]
...

If you want to mount a directory from the host system to have it locally available in the container, use Docker volumes.

Here is a sample command that maps the /absolute/path/to/directory/no/trailing/slash directory from the host system to the /path/inside/container inside the container.

docker run -it -v /absolute/path/to/directory/no/trailing/slash:/path/inside/container docker.pkg.github.com/graalvm/container/community:20.2.0 bash

If you want to create docker images that contain GraalVM Ruby, R, or Python implementation, you can use a Dockerfile like the example below, which uses docker.pkg.github.com/graalvm/container/community:20.2.0 as the base image, installs Ruby support using the gu utility, then creates and runs a sample Ruby program.

FROM docker.pkg.github.com/graalvm/container/community:20.2.0
RUN gu install ruby
WORKDIR /workdir
RUN echo 'puts "Hello from Truffleruby!\nVersion: #{RUBY_DESCRIPTION}"' > app.rb
CMD ruby app.rb

If you put the above snippet in a Dockerfile in the current directory, you can build and run it with the following commands:

docker build -t truffleruby-demo .
...
$ docker run -it --rm truffleruby-demo
Hello from Truffleruby!
Version: truffleruby 20.2.0, like ruby 2.6.6, GraalVM CE Native [x86_64-darwin]

New Users #

Since this Getting Started guide is intended mainly for users new to GraalVM, or users who are familiar with GraalVM but may have little experience using it, please consider investigating more complex Example Applications. We also recommend checking our GraalVM Team Blog.

Advanced Users #

If you are mostly interested in GraalVM support for a specific language, or want more in-depth details about GraalVM’s diverse technologies, proceed to Reference Manuals.

If you are looking for tooling support GraalVM Enterprise offers, proceed to Debugging and Monitoring Tools.

If you are considering GraalVM as a platform for your future language or tool implementation, go to GraalVM Enterprise as a Platform.

You can find information on GraalVM’s security model in the Security Guide, and rich API documentation in GraalVM SDK Javadoc.