Developer's Note:

The CommandAPI hasn't been released for Velocity yet. We do, however, offer snapshot builds. This small section on Velocity will outline how to get the snapshot builds and what limitations the CommandAPI currently has on Velocity.

This page focuses on outlining how to set up the CommandAPI for Velocity. It expects that you are already familiar with how to set up a Velocity plugin.

Adding the snapshot repository with Maven or Gradle

Because we do not have an official release yet, the snapshot builds are not published in the Maven Central repository. Instead you need to add our snapshot repository:

repositories {
    maven {
        url = ""
repositories {
    maven {
        url = uri("")

Adding the dependency

As mentioned, Velocity can only be accessed with snapshot builds. These snapshot build version are following standard semantic versioning and thus have the -SNAPSHOT suffix:

dependencies {
    compile "dev.jorel:commandapi-velocity-shade:9.4.0-SNAPSHOT"
dependencies {

Setting up the CommandAPI

The CommandAPI requires two steps: loading and enabling. We will perform these steps in Velocity's loading stages, construction and initialization. These two stages are explained in their documentation. We will perform the CommandAPI's loading step in the construction phase first:

public ExamplePlugin(ProxyServer server, Logger logger) {
    this.server = server;
    this.logger = logger;

    CommandAPI.onLoad(new CommandAPIVelocityConfig(server, this));

Next, we want to utilize Velocity's ProxyInitializeEvent to perform the CommandAPI's enabling step:

public void onProxyInitialization(ProxyInitializeEvent event) {
    // Any CommandAPI command registrations...

Current limitations

The CommandAPI currently only offers support for a very limited amount of arguments on Velocity. This is because arguments are primarily implemented on the backend servers. However, the CommandAPI offers access for the primitive type arguments:

Registering a simple command

Command registration works the same way as it does in Bukkit. To visualize this, we want to register a simple command that generates a random number between a chosen minimum and a chosen maximum value:

Example - Registering a simple command

We want to register the command /randomnumber with the following syntax:

/randomnumber <min> <max>

To accomplish that, we register the command like this:

new CommandAPICommand("randomnumber")
    .withArguments(new IntegerArgument("min"))
    .withArguments(new IntegerArgument("max"))
    .executesPlayer((player, args) -> {
        int min = (int) args.get("min");
        int max = (int) args.get("max");
        Random random = ThreadLocalRandom.current();
        int randomNumber = random.nextInt(min, max);
        player.sendMessage(Component.text().content("Your random number is: " + randomNumber));
    .executesPlayer(PlayerCommandExecutor { player, args ->
        val min = args["min"] as Int
        val max = args["max"] as Int
        val random = ThreadLocalRandom.current()
        val randomNumber = random.nextInt(min, max)
        player.sendMessage(Component.text().content("Your random number is: $randomNumber"))