> For the complete documentation index, see [llms.txt](https://docs.ohalee.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ohalee.com/products/obsidian-license/multiple-jars.md).

# Several Jars, One License

Ship a lobby plugin and a game plugin under one product and one license key, and let each server pull the jar it needs.

A network plugin is often not one jar. A bedwars product ships a lobby plugin and a game plugin. A survival product might ship a proxy jar and a backend jar. An add-on pack might ship four.

Before, each of those needed its own product and its own key, so a customer who bought "the plugin" ended up holding three unrelated licenses and you answered three support tickets. Now one product can hold several **jars**, one license covers all of them, and each server names the one it wants.

## Naming your jars

A jar name is a short label you choose: `lobby`, `game`, `proxy`, `backend`. Lowercase letters, digits, `.`, `-` and `_`.

Upload one build per jar: **Products**, your product, **Upload jar**, and set **Jar name**. The field suggests the names you have already used, so you do not have to remember how you spelled it last time. Leave it empty for a product that ships a single jar, which is what every existing product does.

Each jar keeps its own versions and its own stable and beta channels. Promoting a `lobby` build never touches `game`.

### Uploading by API

The dashboard field is labelled **Jar name**, but the form field on the API is `variant`, the same word the loader config uses. Send anything else and the upload silently lands as the product's single unnamed jar instead of the one you meant:

```bash
curl -sSf -X POST "https://license.ohalee.com/api/dashboard/products/bedwars/payload" \
  -H "Authorization: Bearer $OBSIDIAN_API_KEY" \
  -F "variant=game" \
  -F "version=1.4.0" \
  -F "channel=stable" \
  -F "jar=@build/libs/bedwars-game-payload.jar"
```

Check the result with `obsidian_list_versions`, or **Products**, your product, **Versions**. Each row shows the variant it was filed under, so a typo is obvious immediately.

## Picking a jar on the customer's side

Paper `config.yml`:

```yaml
serverUrl: "https://license.ohalee.com"
licenseKey: "OBS-XXXX-XXXX-XXXX-XXXX"
productId: "bedwars"
serverPublicKey: "..."
variant: "game"        # this server runs the game jar
```

Velocity `config.properties`:

```properties
productId=bedwars
variant=lobby
```

Plain Java:

```java
ObsidianLoader.builder()
        .productId("bedwars")
        .variant("worker")
        ...
```

License check ([the other mode](/products/obsidian-license/license-check.md)) does not need this: it verifies a license and does not download anything, so there is no jar to choose.

## What the customer gets

The same license key, on every server. A bedwars customer puts one key in their lobby servers with `variant: lobby`, and the same key in their game servers with `variant: game`.

Seats count across all of it, because seats are per machine, not per jar. A customer running one lobby and three game servers uses four seats. Size the license accordingly.

## How many jars you can ship

Capped per plan, because it is the feature that turns one product into a whole suite:

| Plan               | Jars per product |
| ------------------ | ---------------- |
| Free and mid plans | 1                |
| Top plan           | Unlimited        |

Only a **new** jar name counts against the limit. Re-uploading an existing one is just a new version and is always allowed, whatever your plan.

Operators self-hosting the platform set this per plan themselves, under **Plans**, `maxJarsPerProduct`. `-1` means unlimited.

## If a loader asks for the wrong jar

The denial says what is actually available rather than just failing:

```
this product has no jar called "lobbby". Available: game, lobby
```

And if a product ships several jars but a loader names none:

```
this product ships several jars, set "variant" in your loader config to one of: game, lobby
```

## Existing products keep working

A product that shipped a single jar before this feature keeps serving it to every loader, whether or not the loader knows about jar names. Nothing to migrate and no config to update.

If you later name your only jar something (say you upload `game` and never had a `default`), loaders that name nothing still get it: one jar is unambiguous. It is only ambiguous once you have two.
