Server

To start ArcadeDB as a server run the script server.sh under the bin directory of ArcadeDB distribution. If you’re using MS Windows OS, replace server.sh with server.bat.

$ bin/server.sh

 █████╗ ██████╗  ██████╗ █████╗ ██████╗ ███████╗██████╗ ██████╗
██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔══██╗██╔════╝██╔══██╗██╔══██╗
███████║██████╔╝██║     ███████║██║  ██║█████╗  ██║  ██║██████╔╝
██╔══██║██╔══██╗██║     ██╔══██║██║  ██║██╔══╝  ██║  ██║██╔══██╗
██║  ██║██║  ██║╚██████╗██║  ██║██████╔╝███████╗██████╔╝██████╔╝
╚═╝  ╚═╝╚═╝  ╚═╝ ╚═════╝╚═╝  ╚═╝╚═════╝ ╚══════╝╚═════╝ ╚═════╝
PLAY WITH DATA                                    arcadedb.com

2025-12-09 22:22:22.839 INFO  [ArcadeDBServer] <ArcadeDB_0> ArcadeDB Server v26.10.2 is starting up...
2025-12-09 22:22:22.841 INFO  [ArcadeDBServer] <ArcadeDB_0> Running on Mac OS X 15.6 - OpenJDK 64-Bit Server VM 25.0.1 (Homebrew)
2025-12-09 22:22:22.843 INFO  [ArcadeDBServer] <ArcadeDB_0> Starting ArcadeDB Server in development mode with plugins [] ...
2025-12-09 22:22:22.878 INFO  [ArcadeDBServer] <ArcadeDB_0> - Metrics Collection Started...
2025-12-09 22:22:22.891 INFO  [ArcadeDBServer] <ArcadeDB_0> Server root path: .
2025-12-09 22:22:22.891 INFO  [ArcadeDBServer] <ArcadeDB_0> Databases directory: ./databases
2025-12-09 22:22:22.891 INFO  [ArcadeDBServer] <ArcadeDB_0> Backups directory: ./backups

+--------------------------------------------------------------------+
|                WARNING: FIRST RUN CONFIGURATION                    |
+--------------------------------------------------------------------+
| This is the first time the server is running. Please type a        |
| password of your choice for the 'root' user or leave it blank      |
| to auto-generate it.                                               |
|                                                                    |
| To avoid this message set the environment variable or JVM          |
| setting `arcadedb.server.rootPassword` to the root password to use.|
+--------------------------------------------------------------------+

Root password [BLANK=auto generate it]: *

The first time the server is running, the root password must be inserted and confirmed. The hash (+salt) of the inserted password will be stored in the file config/server-users.json. The password length must be between 8 and 256 characters. To know more about this topic, look at Security. Delete this file and restart the server to reinsert the password for server’s root user.

The default rules of security are pretty basic. You can implement your own security policy. Check the Security Policy.

You can skip the request for the password by passing it as a setting. Example:

-Darcadedb.server.rootPassword=this_is_a_password

Alternatively the password can be passed file-based. Example:

-Darcadedb.server.rootPasswordPath=/run/secrets/root

which is particularly useful for container-based deployments.

The password file is a plain-text file and should not contain any line breaks / new lines.

Once inserted the password for the root user, you should see this output.

Root password [BLANK=auto generate it]: *********
*Please type the root password for confirmation (copy and paste will not work): *********

2025-12-09 22:23:33.719 INFO  [HttpServer] <ArcadeDB_0> - Starting HTTP Server (host=0.0.0.0 port=[2480, 2489] httpsPort=[2490, 2499])...
2025-12-09 22:23:33.738 INFO  [undertow] starting server: Undertow - 2.3.20.Final
2025-12-09 22:23:33.741 INFO  [xnio] XNIO version 3.8.16.Final
2025-12-09 22:23:33.744 INFO  [nio] XNIO NIO Implementation Version 3.8.16.Final
2025-12-09 22:23:33.803 INFO  [HttpServer] <ArcadeDB_0> - HTTP Server started (host=0.0.0.0 port=2480 httpsPort=2490)
2025-12-09 22:23:33.908 INFO  [ArcadeDBServer] <ArcadeDB_0> Available query languages: [sqlscript, mongo, gremlin, java, cypher, js, graphql, sql]
2025-12-09 22:23:33.909 INFO  [ArcadeDBServer] <ArcadeDB_0> ArcadeDB Server started in 'development' mode (CPUs=8 MAXRAM=4,00GB)
2025-12-09 22:23:33.910 INFO  [ArcadeDBServer] <ArcadeDB_0> Studio web tool available at http://192.168.1.102:2480
A warning WARNING: Using incubator modules: jdk.incubator.vector in the log can be safely ignored.

By default, the following components start with the server:

  • JMX Metrics, to monitor server performance and statistics (served via port 9999).

  • HTTP Server, that listens on port 2480 by default. If port 2480 is already occupied, then the next is taken up to 2489.

In the output above, the name ArcadeDB_0 is the server name. By default, ArcadeDB_0 is used. To specify a different name define it with the setting server.name, example:

$ bin/server.sh -Darcadedb.server.name=ArcadeDB_Europe_0

In a high availability (HA) configuration, it’s mandatory that all the servers in an cluster have different names.

Start server hint

To start the server from a location different than the ArcadeDB folder, for example, if starting the server as a service, set the environment variable ARCADEDB_HOME to the ArcadeDB folder:

$ export ARCADEDB_HOME=/path/to/arcadedb

Server modes

The server can be started in one of three modes, which affect the studio, logging, and security defaults:

Mode Studio Logging WAL Flush LOAD CSV file access

development

Yes

Detailed

No flush (0)

Enabled

test

Yes

Brief

No flush (0)

Enabled

production

No (can be force-enabled)

Brief

Auto-set to 1 if not configured

Auto-disabled if not configured

The mode is controlled by the server.mode setting with a default mode development.

In production mode the Studio web tool is not served by default, to reduce the attack surface. If you need it (for example to inspect a database running in production), force-enable it with the studio.enabled setting:

$ bin/server.sh -Darcadedb.server.mode=production -Darcadedb.studio.enabled=true

When enabling Studio in production, restrict network access to the HTTP port (for example with a firewall, a reverse proxy, or by enabling SSL), since it exposes a web UI on the public-facing server.

Since v26.10.2 Studio’s static files carry an ETag (a digest of their bytes) and answer 304 Not Modified to a matching If-None-Match. Studio pages and the API docs page reference their local scripts and stylesheets as <path>?v=<digest>, and only those versioned URLs are sent Cache-Control: public, max-age=31536000, immutable; pages and unversioned asset URLs are sent no-cache, so the browser revalidates them. Before, assets were cached for one day (max-age=86400) and stylesheets not at all, so after an upgrade a browser could run a fresh page with stale scripts. Now a new version is picked up at once, and a library that did not change stays cached across upgrades. A reverse proxy or CDN in front of the server should honor these headers and keep the query string in its cache key. .png files are now served as image/png.

Production mode defaults

When the server starts in production mode, ArcadeDB automatically applies safe defaults for settings that have not been explicitly configured:

  • WAL flush (arcadedb.txWalFlush): set to 1 (flush without metadata) for transaction durability. If you explicitly set it to 0, a warning is logged. See concepts/transactions.adoc#wal-flush-durability for details.

  • LOAD CSV file access (arcadedb.opencypher.loadCsv.allowFileUrls): disabled to prevent Cypher queries from reading local files on the server. Set to true explicitly if needed.

  • Studio web tool (arcadedb.studio.enabled): the Studio web UI is not served. Set it to true to force-enable Studio in production (see Server modes).

These defaults are only applied when the setting has not been explicitly configured by the user (via system property, environment variable, or API call). Explicit settings are always respected.

At startup, a production checklist is logged summarizing the security-relevant configuration:

INFO  Production checklist:
INFO  - WAL flush: 1 (flush without metadata) [OK]
INFO  - SSL: disabled. Consider enabling for encrypted connections
INFO  - High availability: disabled. Consider enabling for fault tolerance
INFO  - LOAD CSV file access: disabled [OK]
INFO  - Backup support: enabled [OK]
INFO  - Studio web tool: disabled [OK]

Error details in production mode

In production mode no wire surface sends the engine’s own error text to clients. That text can carry stored data (the values of a duplicated key) or details of the server (file paths, URLs), so it is replaced by one generic message, the same on every surface and for every failure: "The request failed. Check the server log for the details". The full error is written to the server log instead. This applies to:

  • HTTP: the detail field is left out of the error response.

  • gRPC: the status description carries the generic message.

  • PostgreSQL: the error message (the M field) carries the generic message. The SQLSTATE code is kept, so drivers still tell a duplicated key (23505) or a syntax error (42601) apart.

  • MongoDB: the protocol words its own error messages and keeps the engine message in the server log.

  • Gremlin Server: the default WebSocket channelizer answers with the generic message. Since v26.10.2 a non-default channelizer, which cannot conceal the text, stops the server from starting in production mode, see Gremlin security.

  • Bolt: the FAILURE message carries the generic message. The Neo4j status code is kept, so drivers still classify and retry the failure. A Cypher syntax error is concealed too, and keeps its Neo.ClientError.Statement.* code.

  • Redis: the text of an error reply after its ERR, TRYAGAIN or NOPERM prefix is the generic message. Errors of the RESP protocol itself, such as wrong number of arguments or value is not an integer or out of range, and the refusal of a credential or a permission stay visible.

  • /ws insert session: the error frames and the message of each entry of a batchAck errors array carry the generic message. The code and the exception class are kept. Text the protocol writes about the request itself, such as a missing keyColumns, an invalid option or an expired session, stays visible, as it is what the client needs to fix the request.

  • /ws change-event subscriptions: the error frames of a failed action carry the generic message.

  • MCP: a tool error, and the Internal error of a JSON-RPC error, carry the generic message. The validation of the tool arguments (a missing database, an unknown tool, a limit out of range) stays visible.

The structured part a client branches on (an error code, a Neo4j status, a RESP prefix, an exception class name) is never concealed, and neither is text the protocol layer writes itself about the request, which carries no stored data. One addition is made in every mode: when an HA replica refuses work that only the leader can run, the answer names the leader, for example The request failed. Check the server log for the details. The leader is server 'arcadedb-0:2480', on every protocol, MCP and the Gremlin Server included. It is a cluster address, not stored data, and it is what tells the client where to retry. The Gremlin Server names the leader’s HTTP address: connect to the Gremlin port of that server. In the server log, a failure the client did not cause is logged at SEVERE with its stack trace, and a failure the client caused (a duplicated key, a syntax error, a validation refusal) is logged with its message only: at INFO, or at FINE for the per-row errors of a /ws insert session, where a bulk load can refuse thousands of rows by design.

The values of a duplicated key are stored data, so they never reach the client in production mode. When a unique index refuses a write, a remote client still receives the exception type, the index name and the existing record’s RID, but DuplicatedKeyException.getKeys() returns [concealed] instead of the key values. HTTP (exceptionArgs), gRPC (the arcadedb-dup-keys trailer), PostgreSQL and MongoDB behave the same way; on Bolt, Redis, the /ws insert session and MCP the whole message is concealed. In development and test mode the key values and the full error messages are returned as before.

Before v26.10.2 the /ws insert session, /ws subscriptions, Bolt, Redis and MCP returned the engine’s error message as is in every mode, duplicated key values included. A client of these protocols that parses the error text receives the generic message in production mode now: branch on the error code, the Neo4j status or the RESP prefix instead, and read the detail from the server log.

User changes on open connections

(Since v26.10.2.) A long-lived connection keeps the user it authenticated as, but the server checks that user again against the current security configuration on every request, as it does for every HTTP call. A user deleted, given a new password, or stripped of a database grant after the connection logged in loses access on its next request instead of keeping it for the life of the connection:

  • PostgreSQL: a deleted or re-passworded user, or one that lost the grant on the connected database, gets a FATAL error with SQLSTATE 28P01 ("Credentials not valid") and the connection is closed.

  • Bolt: a deleted or re-passworded user gets Neo.ClientError.Security.Unauthorized ("The credentials of this connection are no longer valid") and its open transaction is rolled back. A user that lost the grant on the database cannot commit the explicit transaction it opened: it is rolled back.

  • MongoDB: a deleted or re-passworded user is logged out and the command is refused with an Unauthorized error; a user that lost the grant on the database is refused too.

  • Redis: a deleted or re-passworded user is logged out: the command, and every later one, is refused with NOAUTH Authentication required. until the client sends AUTH again.

  • /ws: every frame re-checks the user, for change-event subscriptions and insert sessions alike. A deleted or re-passworded user gets an error frame and the connection is closed with code 1008 ("Principal is no longer valid"); see Streaming Inserts over WebSocket for what happens to an open insert session.

In v26.10.1 and earlier these connections kept the access they had at login until they disconnected.

Create default database(s)

Instead of starting a server and then connect to it, to create the default databases, ArcadeDB Server takes an initial default databases list by using the setting server.defaultDatabases.

$ bin/server.sh "-Darcadedb.server.defaultDatabases=Universe[albert:einstein]"

With the example above the database "Universe" will be created if doesn’t exist, with user "albert", password "einstein".

Due to the use of [], the command line argument needs to be wrapped in quotes.
A default database without users still needs to include empty brackets, ie: -Darcadedb.server.defaultDatabases=Multiverse[]

The users are written to config/server-users.jsonl before they take effect. Since 26.11.1 (issue #10535) a start that has to add a user, or to give an existing user access to the database or one more group, and cannot write that file (a read-only configuration directory, such as a Kubernetes ConfigMap mount) stops with an error naming the file, and nothing is granted in memory that is not on disk. A user that already holds the database under the group the entry names is left alone and nothing is written, so once the first start has made the grants the same entry starts on a read-only directory. Before, the grant of an existing user stayed in force in memory and the failed write was logged as already exists with a different password.

An entry the server cannot parse (no […​] block, a [ or a { never closed) stops the list there: that entry and the ones after it are not loaded, and the server logs a WARNING naming the malformed entry. Since 26.10.2 the WARNING quotes only that entry, with its passwords masked the same way the settings reports mask them (Universe[albert:*], and from the first : on for an entry written without brackets), and an unclosed [ is reported this way instead of aborting the server start.

A database entry may be followed by {restore:<URL>}, which restores that database from a backup archive at start-up, replacing any copy already on disk (e.g. -Darcadedb.server.defaultDatabases=Universe[albert:einstein]{restore:/tmp/universe.zip}).

In a cluster, restore: acts on the node that is starting and on that node only: the other nodes keep their current copy of the database and are not told anything. This is intentional - it is per-node boot configuration, so a rolling restart does not wipe the database cluster-wide - but it does mean a node can come back with different content than its peers. Since 26.10.1 the server logs a WARNING naming the database whenever this replaces a replicated one, so the divergence is visible in the log.

A client can reach the server while it is still booting and start a backup, restore or import of the same database. Since 26.10.1 the restore: command waits for that operation to finish instead of refusing at once, for up to arcadedb.server.startupRestoreSlotWaitMs (60000 ms by default). While it waits the server logs at INFO:

The startup 'restore:' command for database 'Universe' is waiting up to 60000ms for <operation> that was running on it to finish

If the other operation is still running when the wait runs out, the command refuses, the database on disk is left untouched, and the server boot fails. Set the value to 0 (or a negative number) to refuse immediately, as earlier versions did.

Once the server is started, multiple clients can be connected to the server by using one of the supported protocols:

Logging

The log files are created in the folder ./log with the filenames arcadedb.log.X, where X is a number between 0 to 9, set up for log rotate. The current log file has the number 0, and is rotated based on server starts or file size.

By default ArcadeDB does not log debug messages into the console and file. You can change this settings by editing the file config/arcadedb-log.properties. The file is a standard logging configuration file.

The default configuration is the following.

1  handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler
2  .level = INFO
3  com.arcadedb.level = INFO
4  java.util.logging.ConsoleHandler.level = INFO
5  java.util.logging.ConsoleHandler.formatter = com.arcadedb.utility.AnsiLogFormatter
6  java.util.logging.FileHandler.level = INFO
7  java.util.logging.FileHandler.pattern=./log/arcadedb.log
8  java.util.logging.FileHandler.formatter = com.arcadedb.log.LogFormatter
9  java.util.logging.FileHandler.limit=100000000
10 java.util.logging.FileHandler.count=10

Where:

  • Line 1 contains 2 loggers, the console and the file. This means logs will be written in both console (process output) and configured file (see line 7)

  • Line 2 sets INFO (information) as the default logging level for all the Java classes between FINER, FINE, INFO, WARNING, SEVERE

  • Line 3 is as (line 2) but sets the level for ArcadeDB package only SEVERE

  • Line 4 sets the minimum level the console logger filters the log file (below INFO level will be discarded)

  • Line 5 sets the formatter used for the console. The AnsiLogFormatter supports ANSI color codes

  • Line 6 sets the minimum level the file logger filters the log file (below INFO level will be discarded)

  • Line 7 sets the path where to write the log file (the file will have a counter suffix, see line 10)

  • Line 8 sets the formatter used for the file

  • Line 9 sets the maximum file size for the log, before creating a new file. By default it is 100MB

  • Line 10 sets the number of files to keep in the directory. By default it is 10. This means that after the 10th file, the oldest file will be removed

If you’re running ArcadeDB in embedded mode, make sure you’re using the logging setting by specifying the arcadedb-log.properties file at JVM startup:

$ java ... -Djava.util.logging.config.file=$ARCADEDB_HOME/config/arcadedb-log.properties ...

You can also use your own configuration for logging. In this case replace the path above with your own file.

Server Plugins (Extend The Server)

You can extend ArcadeDB server by creating custom plugins. A plugin is a Java class that implements the interface com.arcadedb.server.ServerPlugin:

public interface ServerPlugin {
  void startService();

  default void stopService() {
  }

  default void configure(ArcadeDBServer arcadeDBServer, ContextConfiguration configuration) {
  }

  default void registerAPI(final HttpServer httpServer, final PathHandler routes) {
  }
}

Once registered, the plugin (see below), ArcadeDB Server will instantiate your plugin class and will call the method configure() passing the server configuration. At startup of the server, the startService() method will be invoked. When the server is shut down, the stopService() will be invoked where you can free any resources used by the plugin. The method registerAPI(), if implemented, will be invoked when the HTTP server is initializing where one’s own HTTP commands can be registered. For more information about how to create custom HTTP commands, look at Custom HTTP commands.

Example:

package com.yourpackage;

public class MyPlugin implements ServerPlugin {
  @Override
  public void startService() {
    System.out.println( "Plugin started" );
  }

  @Override
  public void stopService() {
    System.out.println( "Plugin halted" );
  }

  @Override
  default void configure(ArcadeDBServer arcadeDBServer, ContextConfiguration configuration) {
    System.out.println( "Plugin configured" );
  }

  @Override
  default void registerAPI(final HttpServer httpServer, final PathHandler routes) {
    System.out.println( "Registering HTTP commands" );
  }
}

To register your plugin, register the name and add your class (with full package name) in arcadedb.server.plugins setting:

Example:

$ java ... -Darcadedb.server.plugins=MyPlugin:com.yourpackage.MyPlugin ...

In case of multiple plugins, use a comma (,) to separate them.

A common use of a Server Plugin is to register custom Java functions on a standalone server. Since there is no auto-discovery, drop your JAR in lib/ (or lib/plugins/), call database.getSchema().registerFunctionLibrary(…​) from the plugin’s startService() method, and enable the plugin via arcadedb.server.plugins. See User Functions in Java for a complete example.

Metrics

The ArcadeDB server can collect, log and publish metrics. To activate the collection of metrics use the setting:

$ ... -Darcadedb.serverMetrics=true

To log the metrics to the standard output use the setting:

$ ... -Darcadedb.serverMetrics.logging=true

To publish the metrics as Prometheus via HTTP, add the plugin:

$ ... -Darcadedb.server.plugins="Prometheus:com.arcadedb.metrics.prometheus.PrometheusMetricsPlugin"

Then, under http://localhost:2480/prometheus (or the respective ArcadeDB host) the metrics can be requested given server credentials. For details about the response format see the Prometheus docs.