> For the complete documentation index, see [llms.txt](https://lethium.gitbook.io/lethium-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lethium.gitbook.io/lethium-docs/configuration/storage.md).

# Storage and multi-server

Where player data is saved, choosing YAML, SQLite or MySQL, multi-server mode, and Redis.

```yaml
storage:
  type: sqlite
  autosave-seconds: 300
  server-id: ""
  lock-ttl-seconds: 90
  lock-wait-seconds: 15
  lock-denied-message: "clickem.data.lock-denied"
  load-failed-message: "clickem.data.load-failed"
  stash-poll-seconds: 30
  sqlite:
    file: data/clickem.db
  mysql:
    host: localhost
    port: 3306
    database: clickem
    username: clickem
    password: ""
    useSSL: false
    pool-size: 16
```

### Which type?

| `type`   | Best for                                          | Notes                                                                                    |
| -------- | ------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `yaml`   | Tiny servers, testing                             | No setup. One file per player under `plugins/ClickEmCore/data/`. Slow with many players. |
| `sqlite` | **One server** (the default)                      | A single file, `data/clickem.db`. No setup and reliable.                                 |
| `mysql`  | **Several servers** sharing players, or a network | Needs a MySQL or MariaDB database. Enables shared mode, below.                           |

{% hint style="warning" %}
Changing `type` does **not** move existing player data. Plan the choice before launch, or migrate by exporting players first.
{% endhint %}

#### Setting up MySQL

1. Create a database and a user: `CREATE DATABASE clickem; CREATE USER 'clickem'@'%' IDENTIFIED BY 'strong-password'; GRANT ALL ON clickem.* TO 'clickem'@'%';`
2. Fill in `storage.mysql.*`. Set `useSSL: true` if your host supports it.
3. Set a **unique** `storage.server-id` on every server.
4. Set `storage.type: mysql` and restart. Tables are created automatically.

{% hint style="info" %}
MySQL shared mode is new and has not been tested on a real multi-server network yet. Try it on a staging pair of servers first.
{% endhint %}

### Autosave

Player data is saved every `autosave-seconds` (300) and on quit and shutdown. The snapshot is taken on the main thread and written in the background.

### What MySQL mode shares between servers

Only `storage.type: mysql` runs in shared mode. `yaml` and `sqlite` keep everything local.

| Shared                   | How                                                                                                                                                                                                                                                                            |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Player data**          | A **lease lock** per player. The server a player is on holds the lock and renews it every 20 seconds. A second server waits `lock-wait-seconds` (15), then kicks with `lock-denied-message`. After a crash, others may steal the lock once `lock-ttl-seconds` (90) has passed. |
| **Mail-like items**      | A shared stash delivers auction proceeds, gifts and trade items to a player on whichever server they join. Polled every `stash-poll-seconds` (30).                                                                                                                             |
| **Auction House**        | Listings are stored in the database and synced every 5 seconds. Buying or cancelling is atomic, so an item can only be claimed once.                                                                                                                                           |
| **Clans**                | Stored in the database and merged every `clans.sync-seconds` (5). Bank and XP changes are applied as deltas, and withdrawals cannot be double-spent.                                                                                                                           |
| **Offline Vault access** | Other plugins can read and write a player's money even when they are on another server, with short time-outs.                                                                                                                                                                  |

**Not shared** (still per server): live gift offers, live trades, the leaderboards cache, egg and Echo terminal blocks, zones and events.

On the first start in MySQL mode, old `clans.yml`, `auctionhouse.yml`, `gift-returns.yml` and `trade-returns.yml` are imported and renamed `*.migrated`.

#### `server-id`

Must be unique per server. Blank means hostname and port, which is fine for one machine per server.

### Redis (optional)

```yaml
redis:
  enabled: false
  host: localhost
  port: 6379
  username: ""
  password: ""
  database: 0
  ssl: false
  channel: clickem
  share-broadcasts: true
```

Redis lets servers **push updates instantly** instead of waiting for the next poll: stash deliveries, auction and clan changes, lock hand-offs, and shared broadcasts. MySQL polling remains the fallback if Redis is down. It is optional and only useful together with MySQL mode.

`share-broadcasts: true` lets an announcement or achievement broadcast reach all servers. Each player's `server-announcements` setting is honoured.

### If loading a player fails

If a player's saved data cannot be loaded (corrupt row, database hiccup), they are **kicked** with `load-failed-message` instead of being let in on a blank profile. Their saved data is untouched. Fix the cause and they can rejoin.

### Backups

* SQLite: copy `plugins/ClickEmCore/data/clickem.db` while the server is **stopped**, or use SQLite's backup tool.
* MySQL: use `mysqldump`.
* Also back up `data/*.yml` (clans, Auction House, egg blocks, Echo terminals), `leaderboards-cache.yml`, and the whole `modules/` and `lang/` folders.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://lethium.gitbook.io/lethium-docs/configuration/storage.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
