> ## Documentation Index
> Fetch the complete documentation index at: https://docs.grounds.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# Runtime Composition

> Discover and select provider-backed Grounds modules in a Minestom server.

Runtime composition is where a Minestom application selects its active
modules. Classpath discovery finds available providers, but only explicitly
selected providers are installed.

## Build a server

Use `GroundsServer.builder()` from your application entrypoint.

```kotlin theme={null}
import gg.grounds.runtime.core.GroundsServer

fun main() {
    GroundsServer.builder()
        .discoverProviders()
        .useProvider("grounds.agones")
        .start()
}
```

`start()` calls `build()` and starts Minestom. Use `build()` in tests when you
need to inspect composition without starting a server process.

## Discover providers

`discoverProviders()` scans the current thread context classloader with Java
`ServiceLoader`.

```kotlin theme={null}
GroundsServer.builder()
    .discoverProviders()
```

Discovery reports found provider IDs and versions in the runtime logs. If no
providers are found, it reports that result instead.

<Note>
  Discovery does not activate every provider. Select each required provider with
  `useProvider`.
</Note>

## Select a discovered provider

Select a provider by stable module ID:

```kotlin theme={null}
GroundsServer.builder()
    .discoverProviders()
    .useProvider("grounds.agones")
    .build()
```

The ID must match a discovered `GroundsModuleProvider.id`. A missing provider
fails before Minestom starts:

```text theme={null}
Grounds module provider grounds.agones was requested but not discovered. Available providers: none
```

Multiple discovered providers with the same ID also fail as ambiguous. Keep
provider IDs stable and globally unique.

## Use direct providers or modules

Use `use(provider)` when the application creates a provider directly instead
of relying on `ServiceLoader`.

```kotlin theme={null}
GroundsServer.builder()
    .use(ExampleMinigameModuleProvider())
    .build()
```

Direct providers still participate in descriptor validation, service dependency
ordering, and server-type filtering.

Use `use(module)` for a simple module that does not need descriptor metadata:

```kotlin theme={null}
GroundsServer.builder()
    .use(DebugOverlayModule())
    .build()
```

Direct modules are installed after provider-backed modules. Prefer providers
for reusable modules because their descriptors make dependencies and service
contracts visible before startup.

## Configure the runtime

Without an explicit `RuntimeConfig`, the builder reads these environment
variables:

| Variable               | Default    | Values                        |
| ---------------------- | ---------- | ----------------------------- |
| `GROUNDS_SERVER_TYPE`  | `minigame` | `lobby`, `minigame`           |
| `GROUNDS_ENV`          | `dev`      | `dev`, `test`, `prod`         |
| `GROUNDS_BIND_HOST`    | `0.0.0.0`  | Any bind host                 |
| `GROUNDS_BIND_PORT`    | `25565`    | Any integer port              |
| `GROUNDS_SERVER_BRAND` | `Grounds`  | Any server brand              |
| `GROUNDS_ONLINE_MODE`  | `true`     | `true`, `false`               |
| `GROUNDS_PROXY_MODE`   | `auto`     | `auto`, `velocity`, `offline` |

Set `GROUNDS_VELOCITY_FORWARDING_SECRET` when proxy mode is `velocity`; the
runtime rejects forced Velocity mode without it.

Tests can supply configuration directly:

```kotlin theme={null}
import gg.grounds.runtime.RuntimeEnvironment
import gg.grounds.runtime.ServerType
import gg.grounds.runtime.core.RuntimeConfig

GroundsServer.builder()
    .config(RuntimeConfig(serverType = ServerType.MINIGAME, environment = RuntimeEnvironment.TEST))
    .use(ExampleMinigameModuleProvider())
    .build()
```

## Startup and shutdown behavior

When the runtime starts, it:

1. resolves selected discovered providers;
2. filters providers by server type;
3. validates descriptors and service contracts;
4. orders provider-backed modules by dependencies;
5. initializes Minestom and calls `install(ctx)` on every module;
6. starts Minestom on the configured host and port;
7. calls `start()` on every module.

Shutdown calls `stop()` in reverse module order, runs registered shutdown
hooks in reverse registration order, then stops Minestom cleanly.

## Related docs

* [Runtime modules](/reference/development/minestom-runtime/modules)
* [Local modules](/reference/development/minestom-runtime/local-modules)
* [Agones Minestom integration](/reference/plugins/agones/minestom)
