Native Image (Experimental)

ArcadeDB is also distributed as a native executable of the server, compiled ahead of time with GraalVM Native Image. The native server needs no Java runtime, starts in a fraction of a second and uses far less memory than the same server on a JVM, which suits containers, serverless-style deployments and quick local testing.

The native image is an experimental add-on. It does not replace the standard JVM distribution described in how-to/operations/binaries.adoc#binaries and how-to/operations/install-docker.adoc#install-docker, which remains the default, fully supported way to run ArcadeDB and the one the rest of this manual assumes. Use the native image when fast startup and a small memory footprint matter more than having every module available, and treat it as best-effort outside Linux.

Getting the Native Image

Docker images. The native server is published on Docker Hub in the same arcadedata/arcadedb repository as the JVM image, under its own tags:

Tag Content

<version>-native (for example 26.10.2-native)

A release, as a multi-architecture image for linux/amd64 and linux/arm64.

<version>-native-amd64, <version>-native-arm64

The same release for one architecture only.

latest-native

The nightly build of the main branch, a development snapshot. Pin a version tag for anything that matters.

<next-version>-SNAPSHOT-native

The same nightly build, tagged with the version under development.

The nightly tags also exist per architecture (latest-native-amd64, latest-native-arm64 and so on). The two architectures use different base images: the linux/amd64 binary is fully static (musl libc) and runs on an empty scratch image, while the linux/arm64 binary links glibc dynamically and runs on gcr.io/distroless/base-debian12.

Release archives. Each GitHub release carries the native executable for several platforms, each with a .sha256 checksum file:

Platform Asset Status

Linux x86-64

arcadedb-<version>-linux-x86_64.tar.gz

Required for every release. Fully static, runs on any Linux.

Linux ARM64

arcadedb-<version>-linux-aarch_64.tar.gz

Required for every release. Needs glibc on the host.

Windows x86-64

arcadedb-<version>-windows-x86_64.zip

Best-effort: missing from a release whose Windows build failed.

macOS ARM64 (Apple Silicon)

arcadedb-<version>-osx-aarch_64.tar.gz

Best-effort: missing from a release whose macOS build failed.

The archive contains a single executable with the same name as the archive, minus the extension (.exe on Windows). Studio and the configuration templates are embedded in it.

CPU Requirements

A native binary is compiled for one CPU baseline and starts only on a CPU that has every feature of it. native/pom.xml states the baseline explicitly through the native.march property, which a profile sets per build architecture, instead of inheriting the builder’s default. The published images and release archives use these baselines:

Architecture Baseline Required CPU features Excludes, for example

amd64 (Linux, Windows)

x86-64-v3

AVX, AVX2, BMI1, BMI2, FMA, F16C, LZCNT, MOVBE

Intel before Haswell (2013), AMD before Excavator, Atom, Celeron and Pentium parts without AVX, and VMs whose CPU model hides AVX2 (the QEMU default qemu64, the Proxmox defaults x86-64-v2-AES and kvm64)

arm64 (Linux, macOS Apple Silicon)

armv8-a

ASIMD (the ARMv8.0 baseline)

None: runs on every 64-bit ARM core, including the Cortex-A53 and A72 (Raspberry Pi 3 and 4) and Graviton1

x86-64-v3 is also GraalVM 25’s own default on amd64. On arm64 the builder’s own default is armv8.1-a (CRC32 and LSE atomics), and armv8-a is a deliberate choice below it, so that ARMv8.0 cores keep working. (Since v26.11.1: the arm64 baseline was briefly recorded as armv8.1-a, which excluded those cores, and is armv8-a again.) On an older CPU the binary exits as soon as it starts, with:

The current machine does not support all of the following CPU features that are required by the image: [...].
Please rebuild the executable with an appropriate setting of the -march option.

To check a Linux amd64 host, run /lib64/ld-linux-x86-64.so.2 --help: on glibc 2.33 and later it lists x86-64-v3 (supported, searched) when the CPU qualifies. Otherwise look for the avx2, bmi2 and fma flags in /proc/cpuinfo. In a VM, expose the host CPU (-cpu host in QEMU, CPU type host in Proxmox) or a model that supports x86-64-v3.

If the CPU does not qualify, either:

  • download the linux/amd64 compatibility archive of the release, arcadedb-<version>-linux-x86_64-compat.tar.gz, built with -march=compatibility (the default archive is arcadedb-<version>-linux-x86_64.tar.gz). It starts on any x86-64 CPU, including pre-Haswell hardware, QEMU’s qemu64 and Proxmox’s x86-64-v2-AES. It is an archive only: there is no Docker image for it, and the published images keep the baselines in the table above. To run it in a container, build the image yourself with ./native/scripts/build-native-docker.sh --march compatibility,

  • run the JVM image (arcadedata/arcadedb:<version>) or the JVM distribution, whose JIT compiles for the CPU it runs on, or

  • build a native binary for a lower baseline with -Dnative.march=compatibility, which runs on any x86-64 or ARMv8 CPU (see Building the Native Image Yourself).

Running the Native Server

Run the executable directly, passing settings as -D arguments exactly as you would pass them to the JVM:

tar -xzf arcadedb-26.10.2-linux-x86_64.tar.gz
./arcadedb-26.10.2-linux-x86_64 -Darcadedb.server.rootPassword=<your-password>

The server uses the current directory as its root path, so it creates databases/ and its other directories there unless you set arcadedb.server.rootPath. Studio is then available at http://localhost:2480.

To run the Docker image:

mkdir -p databases && sudo chown 1000:1000 databases   # only for a bind mount, see below
docker run --rm -p 2480:2480 -p 5432:5432 \
  -v "$(pwd)/databases:/home/arcadedb/databases" \
  arcadedata/arcadedb:26.10.2-native \
  -Darcadedb.server.rootPassword=<your-password>

The native images differ from the JVM image in a few ways, because neither base image contains a shell:

  • Settings are trailing arguments, not environment variables. The JVM image’s bin/server.sh expands ARCADEDB_SETTINGS and JAVA_OPTS onto the command line. The native image starts the binary directly, so pass -Darcadedb.server.rootPassword=…​ and any other setting as arguments after the image name, as in the example above.

  • User. (Since v26.11.1) Both native images run as UID/GID 1000:1000, the same user as the JVM image, so no --user is needed and a volume written by any of the three images can be mounted by the others. Anonymous and named volumes start owned by 1000:1000 and are writable out of the box. A bind mount keeps the ownership of the host directory, so every bind-mounted path the server writes (databases, but also config and log) must be writable by UID 1000, otherwise the server fails to start with an AccessDeniedException. To run as another UID, pass --user <uid>:<gid> and give that UID ownership of every volume and bind mount, including config and log.

  • Upgrading from an earlier native image. Before v26.11.1 the linux/amd64 image ran as root and the linux/arm64 image as the distroless nonroot user (65532), so the volumes they wrote are owned by those UIDs. Re-own each one once before starting the new image:

    docker run --rm --user 0 -v <volume>:/data busybox chown -R 1000:1000 /data

    The same command makes those volumes usable by the JVM image.

  • Ports. The image exposes 2480 (HTTP API and Studio), 2434 (Raft replication), 5432 (PostgreSQL), 6379 (Redis), 27017 (MongoDB), 7687 (Bolt) and 50051 (gRPC). There is no port 8182, because Gremlin is not included. Publish the ports of the protocol plugins you enable in arcadedb.server.plugins.

  • Volumes. config, databases, backups, replication and log under /home/arcadedb, as in the JVM image.

What the Native Image Includes

  • The SQL and OpenCypher query engines

  • The HTTP API and Studio

  • The PostgreSQL, Redis, MongoDB, Neo4j Bolt and gRPC wire protocols

  • JavaScript scripting through GraalJS (see the security caveat below)

  • The console and graphql modules

  • (Since v26.10.2) Raft high availability, enabled the same way as on the JVM (-Darcadedb.ha.enabled=true and -Darcadedb.ha.serverList=…​): see how-to/operations/ha.adoc#howto-high-availability

  • (Since v26.10.2) Metrics: the Prometheus endpoint (/prometheus, enabled by adding com.arcadedb.metrics.prometheus.PrometheusMetricsPlugin to arcadedb.server.plugins) and OTLP metrics push (-Darcadedb.serverMetrics.otlp.enabled=true)

  • (Since v26.10.2) Tracing: OpenTelemetry spans over OTLP (-Darcadedb.serverMetrics.tracing.enabled=true)

A plugin named in arcadedb.server.plugins that is not in the image is skipped without a log line. If a setting appears to do nothing, check that its module is part of the native image before looking for a configuration mistake.

Limitations Compared to the JVM Distribution

  • No Gremlin. Apache TinkerPop is not part of the native build. If you need Gremlin, use the JVM distribution.

  • No SIMD vector math. (Since v26.10.2) A native image does not compile the Java Vector API into SIMD instructions, so ArcadeDB switches vector index builds, vector functions, Graph OLAP and time series to their scalar implementations when it detects a native image. Results are identical, but vector-heavy workloads run slower than on the JVM, where the Vector API is compiled to SIMD. To force a different JVector provider anyway, set the jvector.vectorization_provider system property.

  • Thai full-text analyzer. org.apache.lucene.analysis.th.ThaiAnalyzer fails with "This JRE does not have support for Thai segmentation", because the JDK’s Thai dictionary is not available in the image. The other analyzers work.

  • JavaScript is not hardened for untrusted callers. Embedding GraalJS required relaxing a Truffle safety check for a few standard builtins (Atomics.*, SharedArrayBuffer, TypedArray.prototype.set), and any authenticated user who can run js commands can reach them. Do not expose the native image’s JavaScript surface to untrusted users in a shared or multi-tenant deployment.

  • Certificate trust store. The image carries a snapshot of the build machine’s JDK cacerts trust store, taken at build time. The CA bundle copied into the Docker images serves only code paths that read the operating system’s bundle explicitly; it does not change the trust anchors baked into the binary.

  • Size. The executable is large, around 907 MiB on macOS ARM64, because every classpath resource, including the Studio assets, is embedded in it.

Building the Native Image Yourself

Most users should download a published binary or image. Two scripts in the ArcadeDB source tree build one. build-native.sh needs GraalVM Community Edition 25.0.2 installed (the exact version the build pins), with both JAVA_HOME and GRAALVM_HOME pointing at the GraalVM home. build-native-docker.sh needs only Docker: it fetches the pinned GraalVM into a throwaway builder image.

./native/scripts/build-native.sh               # binary for the current platform
./native/scripts/build-native-docker.sh        # Linux Docker image for the current architecture

By default the build targets the baseline of the published binaries (see CPU Requirements). To build for an older CPU, lower it: compatibility runs on any x86-64 or ARMv8 CPU, and x86-64-v2 (amd64 only) needs SSE4.2 and POPCNT but no AVX. A lower baseline gives up the AVX2, FMA and BMI2 (or LSE) code of the default build.

./native/scripts/build-native.sh -- -Dnative.march=compatibility
./native/scripts/build-native-docker.sh --march compatibility
mvn -Pnative -pl native -am -DskipTests -Dnative.march=compatibility package

Do not distribute a binary built with -march=native: it requires every feature of the CPU that built it.

Native Image cannot cross-compile: each build produces a binary for the platform it runs on, and build-native-docker.sh builds the Linux binary inside a container so it also works on macOS. The build is memory hungry. build-native-docker.sh requires a Docker VM with about 16 GiB of memory, and for a local build-native.sh you can set the builder heap with NATIVE_IMAGE_OPTIONS="-J-Xmx24g" if the default runs out of memory. See docs/native-image.md in the ArcadeDB repository for the full build reference.