LegacyShell WikiLegacyShell Wiki
Back to LegacyShell
Home
Wiki
Plugins
Docs
Back to LegacyShell
Home
Wiki
Plugins
Docs
  • Documentation

    • Getting Started

      • What is LegacyShell?
      • Speed Setup
      • Requirements
      • Installation
      • First Run
      • Config Files
      • Making an Account
      • Troubleshooting (Getting Started)
    • Running a Server

      • Architecture Overview
      • The Database
      • Users and Ranks
      • Adding Game Servers
      • Client Mirrors
      • Perpetual
      • Backups
      • Rate Limiting
      • Moderation
      • Closed Mode
      • Deployment
      • Troubleshooting (Running a Server)
      • Hosting for Someone Else's Instance
    • Content Creation

      • Maps
      • Dealing with Babylon Models
      • Map Blocks
      • Items and Skins
      • Hats and Stamps
      • Sounds
      • Gamemodes
      • Seasonal Events
    • Plugin Development

      • Quickstart
      • I Want To...
      • Anatomy of a Plugin
      • Lifecycle
      • Dependencies
      • Events (Concept)
      • Event Reference

        • services: events
        • game: events — shared logic (src/shell/)
        • game: events — main-thread server process
        • game: events — per-connection client object
        • game: events — room lifecycle & tick loop
        • game: events — in-browser gameplay
        • client: events — client server & build pipeline
      • Commands
      • Client-Side Code
      • Static Assets
      • Content Packs
      • Networking
      • Workers and State
      • Prediction and Authority
      • Recipes

        • Recipe: Killstreaks
        • Recipe: New Pickup Item
        • Recipe: New Gamemode
        • Recipe: Custom Weapon
        • Recipe: UI Modification
        • Recipe: Discord Integration
        • Recipe: Replacing Core Behaviour
        • Recipe: Persistent Plugin Storage
        • Recipe: Rewarding Players with Currency
        • Recipe: Custom Per-Player Data
        • Recipe: Custom Theme
      • Publishing
      • Pitfalls
      • Modifiers
      • Sound and Apollo
    • Codebase Reference

      • Repo Layout
      • Shared Shell Layer
      • Server-Only Markers
      • The ss Object
      • Build Pipeline
      • Stamps and Babylons
      • Game Loop
      • Rooms and Workers
      • Wire Protocol
      • Generated

        • Wire Protocol Opcodes
        • Enums & Lookup Tables
        • Database Schema
        • Config Reference
        • Slash Command Reference
      • Services Internals
      • Catalog and Items
      • Permissions Internals
      • Physics and Collision
      • Known Quirks
      • Codebase Anecdotes
      • Development Timeline
    • Contributing

      • Documentation Style Guide
      • Generators
      • For AI Agents

Backups

Audience: Server operators · Prereqs: The Database

Canonical source: server-services/src/data_management/backups.js

Services backs up its own SQLite database automatically - no separate tooling needed, but worth understanding exactly what it does and doesn't protect against.

How it works

createBackup() runs once at services boot, and then on the interval set by store/config/services.yaml's backups.interval (in hours, default 4). Each run:

  1. Checks the most recently modified file already in the backup folder. If it's younger than backups.interval hours old, the run is skipped entirely (logged as "Backup already exists for this time") - this makes the interval a minimum spacing, not a guaranteed schedule; if services restarts frequently, you won't get a flood of near-duplicate backups.
  2. Otherwise, does a raw file copy of the live database (fs.readFileSync → fs.writeFileSync) to a timestamped filename: LegacyShellDataBackup-<YYYY-MM-DD>_<HH-MM-SS>.db.
  3. Prunes the oldest backups beyond backups.keep (default 50), sorted by file modification time.

Where backups go

store/backups/ by default, or wherever backups.filepath in services.yaml points if set. See the generated config reference for the exact keys.

What this does and doesn't protect against

Because it's a raw file copy (not SQLite's own online-backup API), it's a straightforward snapshot - fine for the common failure modes (accidental bad UPDATE/DELETE, a corrupted upgrade, wanting to roll back after testing something on your live database). It is not protection against the backup folder itself being lost - store/backups/ lives on the same disk as the live database by default, so a full disk failure takes both. If that matters to you, point backups.filepath somewhere off-machine (a mounted network drive, a synced folder) or add your own off-box copy of that directory on top of this.

It's also not a replacement for stopping services before a risky manual edit - see the warning in The Database. A backup lets you recover from a mistake; it doesn't prevent one from corrupting data mid-write.

Restoring a backup

Stop the services server, then replace the live database file with a backup:

cp store/backups/LegacyShellDataBackup-2026-08-15_04-00-00.db server-services/store/LegacyShellData.db

(Adjust paths to match your actual backups.filepath and DB location.) Restart services once the file is replaced. There's no in-app restore flow - it's a plain file swap.

Common Issues

Backups aren't being created. Check backups.enabled is true in services.yaml, and check the services server's own log output at boot and on each interval tick - a permissions issue on the backup folder logs an error there rather than failing silently.

The backup folder is growing larger than expected. backups.keep only limits count, not total size - 50 backups of a large, heavily-populated database (many users, items, maps) can add up. Lower backups.keep or move to a filepath with more room if this becomes an issue.

Next: Rate Limiting.


This page was drafted with AI assistance and reviewed for accuracy. If something looks wrong, please open a PR or flag it.

Edit this page on GitHub
Prev
Perpetual
Next
Rate Limiting