**Straight answer**
Cross-server is **not** “I added a JDBC URL.”
- **SQL (MySQL / SQLite)** stores **durable state** — rows that survive restarts: team membership, home coordinates, bounty amounts, balance snapshots.
- **Redis** (or another message bus the plugin documents) carries **live events** — invites, chat relay, cache invalidate, “something changed on backend A, tell backend B now.”
If you only configure MySQL, transfer via Velocity, and then see split-brain invites, ghost team chat, or double bounty behavior, you are missing the live layer — not “doing SQL wrong.”
This explainer is the mental model and staging checklist. Product canons stay on their resource pages (for example DonutTeams): https://shyam.studio/resources/donutteams-cross-server-folia-teams.20/
---
**Mental model**
| Layer | Role | Typical contents | Without it you see… |
|---|---|---|---|
| SQL (MySQL/SQLite) | Source of truth / durable state | Team rows, homes coords, bounty amounts, balances snapshots | Data loss on restart; empty after wipe |
| Redis | Events, cache invalidate, pub/sub | Invite created, member joined, chat relay, home changed, kill claimed | Desync until restart; ghost chat; double actions |
**Caption:** SQL remembers; Redis notifies.
---
**Diagram (ASCII)**
```
+------------------+
| Velocity |
| (proxy) |
+--------+---------+
|
+-----------------+-----------------+
| |
v v
+---------------+ +---------------+
| Backend A | | Backend B |
| Folia | | Folia |
+-------+-------+ +-------+-------+
| |
| write/read durable rows |
+----------> MySQL <----------------+
(SQL)
| publish / subscribe events |
+----------> Redis <----------------+
invite / chat / invalidate
```
Both backends share one MySQL for durable truth. Both publish and subscribe on Redis so a change on A is visible on B **before** the next restart. Velocity moves the player; SQL + Redis keep plugin state coherent.
---
**Failure modes you will recognize**
These are the symptoms that usually mean “SQL only, no live bus” (or a misconfigured bus):
1. **Split-brain invites** — Player accepts a team invite on backend A; backend B still shows the invite as pending until restart or a lucky refresh.
2. **Ghost team chat** — Messages appear only on the writer’s server; teammates on other backends see silence.
3. **Stale team home after transfer** — Home was moved on A; after a Velocity hop to B the old coordinates still win until cache dies.
4. **Double bounty payout / duplicate kill handling** — A death is processed on more than one backend, or a claim is not invalidated network-wide, so rewards or claim state diverge.
None of these prove MySQL is “broken.” They prove **live invalidate/notify** never reached the other process.
---
**Staging checklist (two Folia backends + proxy)**
Run this before you call the network “cross-server ready.” Adapt names to your SKUs; the shape matches S Teams-style verification:
1. **Joins** — Create a team on A; join from B; confirm membership on both without restart.
2. **Roles / permissions** — Promote or demote on A; confirm the role is visible on B immediately.
3. **Team chat relay** — Speak on A; teammates on B receive the message.
4. **Team homes / personal homes handoff** — Set or move a team home on A; transfer to B; teleport still resolves correctly. If you also run personal homes, confirm `/home` and `/team home` do not fight.
5. **Full Velocity transfers both directions** — A→B and B→A with an active team session; no ghost invites, no missing chat, no stale home.
6. **After Redis restart** — Bounce Redis; reconnect plugins; repeat join + chat + transfer smoke tests.
7. **After MySQL failover drill** (if you have one) — Confirm durable rows return; then confirm Redis bus is still reachable so you do not ship “SQL recovered, live sync dead.”
Document which plugin owns `/team*`, `/home*`, `/tpa*`, `/rtp`, `/bounty*` so staging failures are not “two plugins fighting” mistaken for “Redis is optional.”
---
**Worked example — S Teams / DonutTeams**
S Teams / DonutTeams requirements call out **MySQL (network durable state)** and **Redis (cross-server messaging)**. That pairing matches the mental model above: teams rows live in SQL; invites, membership events, and chat relay need the Redis path.
When you evaluate:
- Point every Folia backend at the **same** MySQL database.
- Point every backend at the **same** Redis instance (or cluster) the product docs describe.
- Run the staging checklist above before opening transfers to players.
Product CTAs:
- https://shyam.studio/bbb-products/s-teams-cross-server-x-folia-teams.45/
- https://shyam.studio/resources/donutteams-cross-server-folia-teams.20/
- BBB: https://builtbybit.com/resources/s-teams-cross-server-x-folia-teams.47187/
Chooser guide (when you are still picking a teams plugin): https://shyam.studio/threads/how-to-choose-a-cross-server-teams-plugin.38/
---
**Worked example — Bounty**
Bounty’s cross-server / Folia positioning emphasizes **persisting targets and rewards in SQL** (shared authoritative database) and making sure a kill cannot be paid twice. Frame evaluation around:
- Shared SQL so every backend sees the same bounty rows.
- **Duplicate-claim tests:** one valid death pays **at most once** across backends (kill on A, no second payout if B also observes the death or a late event).
- Transfer mid-fight / mid-claim scenarios in staging.
Do not invent a Redis requirement for Bounty unless the current product listing explicitly requires it. Other network SKUs (for example S Teams) still need Redis for live messaging — check each product’s docs.
Product CTAs:
- https://shyam.studio/bbb-products/bounty-cross-server-folia.48/
- BBB: https://builtbybit.com/resources/ultrabounty-donutsmp-bounties-x-folia.54738/
---
**Same class of network problem (mention only)**
Other Shyam network SKUs hit the same durable-vs-live design space. Confirm storage options on each listing before you copy a Teams Redis setup blindly:
- **Orders** — cross-server player orders; site/resources mention MySQL, MongoDB, Redis — https://shyam.studio/bbb-products/orders-cross-server-player-orders.69/ · https://shyam.studio/resources/orders-cross-server-player-orders.16/
- **Crates** — cross-server crates Folia SKU — https://shyam.studio/bbb-products/crates-cross-server-crates-folia.37/
Treat these as “same class of problem,” not as a second deep dive.
---
**Practical takeaways**
1. Adding MySQL is necessary for durable network state — it is **not** by itself a complete cross-server sync story for every plugin.
2. When product docs require Redis for messaging/invalidate, skipping Redis is how you buy split-brain invites and ghost chat.
3. Stage with **two backends + Velocity transfers**, not “works on one Folia test jar.”
4. For runtime Folia context (threading, plugin safety), see: https://shyam.studio/threads/best-folia-plugins-for-minecraft-servers.42/
---
**Browse & support**
- BuiltByBit store: https://builtbybit.com/store/shyam-studio.187/
- Discord license/support: use the Discord link on each product page.
Cross-server is **not** “I added a JDBC URL.”
- **SQL (MySQL / SQLite)** stores **durable state** — rows that survive restarts: team membership, home coordinates, bounty amounts, balance snapshots.
- **Redis** (or another message bus the plugin documents) carries **live events** — invites, chat relay, cache invalidate, “something changed on backend A, tell backend B now.”
If you only configure MySQL, transfer via Velocity, and then see split-brain invites, ghost team chat, or double bounty behavior, you are missing the live layer — not “doing SQL wrong.”
This explainer is the mental model and staging checklist. Product canons stay on their resource pages (for example DonutTeams): https://shyam.studio/resources/donutteams-cross-server-folia-teams.20/
---
**Mental model**
| Layer | Role | Typical contents | Without it you see… |
|---|---|---|---|
| SQL (MySQL/SQLite) | Source of truth / durable state | Team rows, homes coords, bounty amounts, balances snapshots | Data loss on restart; empty after wipe |
| Redis | Events, cache invalidate, pub/sub | Invite created, member joined, chat relay, home changed, kill claimed | Desync until restart; ghost chat; double actions |
**Caption:** SQL remembers; Redis notifies.
---
**Diagram (ASCII)**
```
+------------------+
| Velocity |
| (proxy) |
+--------+---------+
|
+-----------------+-----------------+
| |
v v
+---------------+ +---------------+
| Backend A | | Backend B |
| Folia | | Folia |
+-------+-------+ +-------+-------+
| |
| write/read durable rows |
+----------> MySQL <----------------+
(SQL)
| publish / subscribe events |
+----------> Redis <----------------+
invite / chat / invalidate
```
Both backends share one MySQL for durable truth. Both publish and subscribe on Redis so a change on A is visible on B **before** the next restart. Velocity moves the player; SQL + Redis keep plugin state coherent.
---
**Failure modes you will recognize**
These are the symptoms that usually mean “SQL only, no live bus” (or a misconfigured bus):
1. **Split-brain invites** — Player accepts a team invite on backend A; backend B still shows the invite as pending until restart or a lucky refresh.
2. **Ghost team chat** — Messages appear only on the writer’s server; teammates on other backends see silence.
3. **Stale team home after transfer** — Home was moved on A; after a Velocity hop to B the old coordinates still win until cache dies.
4. **Double bounty payout / duplicate kill handling** — A death is processed on more than one backend, or a claim is not invalidated network-wide, so rewards or claim state diverge.
None of these prove MySQL is “broken.” They prove **live invalidate/notify** never reached the other process.
---
**Staging checklist (two Folia backends + proxy)**
Run this before you call the network “cross-server ready.” Adapt names to your SKUs; the shape matches S Teams-style verification:
1. **Joins** — Create a team on A; join from B; confirm membership on both without restart.
2. **Roles / permissions** — Promote or demote on A; confirm the role is visible on B immediately.
3. **Team chat relay** — Speak on A; teammates on B receive the message.
4. **Team homes / personal homes handoff** — Set or move a team home on A; transfer to B; teleport still resolves correctly. If you also run personal homes, confirm `/home` and `/team home` do not fight.
5. **Full Velocity transfers both directions** — A→B and B→A with an active team session; no ghost invites, no missing chat, no stale home.
6. **After Redis restart** — Bounce Redis; reconnect plugins; repeat join + chat + transfer smoke tests.
7. **After MySQL failover drill** (if you have one) — Confirm durable rows return; then confirm Redis bus is still reachable so you do not ship “SQL recovered, live sync dead.”
Document which plugin owns `/team*`, `/home*`, `/tpa*`, `/rtp`, `/bounty*` so staging failures are not “two plugins fighting” mistaken for “Redis is optional.”
---
**Worked example — S Teams / DonutTeams**
S Teams / DonutTeams requirements call out **MySQL (network durable state)** and **Redis (cross-server messaging)**. That pairing matches the mental model above: teams rows live in SQL; invites, membership events, and chat relay need the Redis path.
When you evaluate:
- Point every Folia backend at the **same** MySQL database.
- Point every backend at the **same** Redis instance (or cluster) the product docs describe.
- Run the staging checklist above before opening transfers to players.
Product CTAs:
- https://shyam.studio/bbb-products/s-teams-cross-server-x-folia-teams.45/
- https://shyam.studio/resources/donutteams-cross-server-folia-teams.20/
- BBB: https://builtbybit.com/resources/s-teams-cross-server-x-folia-teams.47187/
Chooser guide (when you are still picking a teams plugin): https://shyam.studio/threads/how-to-choose-a-cross-server-teams-plugin.38/
---
**Worked example — Bounty**
Bounty’s cross-server / Folia positioning emphasizes **persisting targets and rewards in SQL** (shared authoritative database) and making sure a kill cannot be paid twice. Frame evaluation around:
- Shared SQL so every backend sees the same bounty rows.
- **Duplicate-claim tests:** one valid death pays **at most once** across backends (kill on A, no second payout if B also observes the death or a late event).
- Transfer mid-fight / mid-claim scenarios in staging.
Do not invent a Redis requirement for Bounty unless the current product listing explicitly requires it. Other network SKUs (for example S Teams) still need Redis for live messaging — check each product’s docs.
Product CTAs:
- https://shyam.studio/bbb-products/bounty-cross-server-folia.48/
- BBB: https://builtbybit.com/resources/ultrabounty-donutsmp-bounties-x-folia.54738/
---
**Same class of network problem (mention only)**
Other Shyam network SKUs hit the same durable-vs-live design space. Confirm storage options on each listing before you copy a Teams Redis setup blindly:
- **Orders** — cross-server player orders; site/resources mention MySQL, MongoDB, Redis — https://shyam.studio/bbb-products/orders-cross-server-player-orders.69/ · https://shyam.studio/resources/orders-cross-server-player-orders.16/
- **Crates** — cross-server crates Folia SKU — https://shyam.studio/bbb-products/crates-cross-server-crates-folia.37/
Treat these as “same class of problem,” not as a second deep dive.
---
**Practical takeaways**
1. Adding MySQL is necessary for durable network state — it is **not** by itself a complete cross-server sync story for every plugin.
2. When product docs require Redis for messaging/invalidate, skipping Redis is how you buy split-brain invites and ghost chat.
3. Stage with **two backends + Velocity transfers**, not “works on one Folia test jar.”
4. For runtime Folia context (threading, plugin safety), see: https://shyam.studio/threads/best-folia-plugins-for-minecraft-servers.42/
---
**Browse & support**
- BuiltByBit store: https://builtbybit.com/store/shyam-studio.187/
- Discord license/support: use the Discord link on each product page.