> For the complete documentation index, see [llms.txt](https://lethium.gitbook.io/origin-smp/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/origin-smp/stackmaster/storage-and-sync.md).

# Storage

What StackMaster saves and where, choosing SQLite, MySQL, YAML or JSON, auto-save, and why there is no multi-server sync.

## What is saved where

| Stack                                                  | Saved in                                                          | Survives a restart  |
| ------------------------------------------------------ | ----------------------------------------------------------------- | ------------------- |
| **Spawner stacks**                                     | The storage below (`data.db` by default)                          | Yes                 |
| **Spawner upgrades, owner, spawn mode, custom delays** | The spawner block itself (block data)                             | Yes                 |
| **Mob stacks**                                         | The mob itself (persistent data `stackmaster:stack_size`)         | Yes, with the world |
| **Item piles**                                         | The item entity itself (persistent data `stackmaster:stack_size`) | Yes, with the world |

So the storage only holds **spawner stacks**: world, position and size of each stack, plus a small copy of the spawner's settings. Everything else travels with the world files.

## The settings

```yaml
storage:
  type: sqlite
  auto-save: true
  auto-save-interval-seconds: 30
  save-spawners-immediately: true
  save-on-shutdown: true
  sqlite:
    file: "data.db"
    busy-timeout-ms: 5000
    synchronous: normal
    journal-mode: wal
  mysql:
    host: localhost
    port: 3306
    database: stackmaster
    username: YOUR-USER
    password: "YOUR-PASSWORD"
    table-prefix: "stackmaster_"
    use-ssl: false
    connection-timeout-ms: 5000
```

## Which type?

| `type`                 | Best for                                                                | Where the data goes                                                                          |
| ---------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
| `sqlite`               | **One server** (the default)                                            | One file, `plugins/StackMaster/data.db`, table `stacks`.                                     |
| `mysql` (or `mariadb`) | Keeping the data outside the server files, on a MySQL or MariaDB server | Table `<table-prefix>stacks`, `stackmaster_stacks` by default. Created on the first connect. |
| `yaml`                 | Small servers, readable files                                           | One file per stack: `plugins/StackMaster/stacks/<world>/<x>_<y>_<z>.yml`.                    |
| `json`                 | Small and medium servers                                                | One file per stack: `plugins/StackMaster/stacks/<world>/<x>_<y>_<z>.json`.                   |

The SQLite driver, the MySQL driver and Gson are downloaded by Paper on the first start. Nothing has to be installed by hand.

If the chosen type cannot start (for example MySQL is unreachable), StackMaster logs `Could not initialize mysql storage (...), falling back to SQLite.` and uses `data.db` for that run.

{% hint style="warning" %}
**Changing `type` does not move existing data.** Spawner stacks saved in the old storage are not found in the new one. Their blocks are then treated as plain, untracked spawners: the stack size is lost. Pick the type before players place spawners.
{% endhint %}

## Auto-save

| Key                          | Default | What it does                                                                            |
| ---------------------------- | ------- | --------------------------------------------------------------------------------------- |
| `auto-save`                  | `true`  | Write changed stacks on a timer.                                                        |
| `auto-save-interval-seconds` | `30`    | The timer, in real seconds.                                                             |
| `save-spawners-immediately`  | `true`  | Write a spawner stack the moment it changes (placed, added to, broken).                 |
| `save-on-shutdown`           | `true`  | In the file, no effect. Pending data is always written on shutdown and on `/sm reload`. |

These timers apply to `sqlite` and `mysql`. `yaml` and `json` write every change to its file right away. All writing happens on a background thread, never on the server thread.

## SQLite settings

| Key                      | Default   | What it does                                                           |
| ------------------------ | --------- | ---------------------------------------------------------------------- |
| `sqlite.file`            | `data.db` | File name inside `plugins/StackMaster/`.                               |
| `sqlite.busy-timeout-ms` | `5000`    | How long to wait for a locked database.                                |
| `sqlite.synchronous`     | `normal`  | `off`, `normal` or `full`. `normal` is the safe, fast choice.          |
| `sqlite.journal-mode`    | `wal`     | `delete`, `truncate`, `persist`, `memory`, `wal` or `off`. Keep `wal`. |

## MySQL settings

| Key                           | Default        | What it does                         |
| ----------------------------- | -------------- | ------------------------------------ |
| `mysql.host`                  | `localhost`    | Database server address.             |
| `mysql.port`                  | `3306`         | Database server port.                |
| `mysql.database`              | `stackmaster`  | Database name. It must exist.        |
| `mysql.username`              | `root`         | Database user.                       |
| `mysql.password`              | `""`           | Database password.                   |
| `mysql.table-prefix`          | `stackmaster_` | Prefix of the table name.            |
| `mysql.use-ssl`               | `false`        | Use TLS when the database offers it. |
| `mysql.connection-timeout-ms` | `5000`         | Connection time-out.                 |

## Setting up MySQL

{% stepper %}
{% step %}

### Create a database and a user

```sql
CREATE DATABASE stackmaster;
CREATE USER 'YOUR-USER'@'%' IDENTIFIED BY 'YOUR-PASSWORD';
GRANT ALL ON stackmaster.* TO 'YOUR-USER'@'%';
```

{% endstep %}

{% step %}

### Fill in `storage.mysql`

Set `host`, `port`, `database`, `username` and `password`. With `use-ssl: true` the connection uses TLS when the server offers it.
{% endstep %}

{% step %}

### Switch the type

Set `storage.type: mysql` and restart (or `/sm reload`). The table is created automatically.
{% endstep %}
{% endstepper %}

If the connection drops, StackMaster reconnects on its own and logs `Reconnecting to MySQL...`.

## Several servers

StackMaster has **no multi-server sync**. Each server keeps its own stacks. Mob stacks, item piles and spawner upgrades live in each server's world files anyway.

Stacks are stored by **world name and block position**. Two servers that share one MySQL table and have worlds with the same names would read and overwrite each other's rows. Give every server its own database or its own `table-prefix`.

## Backups

* **SQLite:** copy `plugins/StackMaster/data.db` while the server is stopped (with WAL mode also `data.db-wal` and `data.db-shm` if they exist).
* **MySQL:** `mysqldump` the database.
* **YAML / JSON:** copy the `plugins/StackMaster/stacks/` folder.
* Back up the worlds at the same time. Upgrades and mob stacks are stored there, and a spawner stack row without its block is deleted when its chunk loads.
