Database Updates / Migrations¶
XC_VM uses a file-based DB update system to manage schema changes between versions. DB updates run automatically during panel updates and system status checks, and can be applied by hand with db:migrate.
For the console entry point, command registry and how to register a command, see CLI Tools & Console Reference.
How It Works¶
-
SQL files for DB updates are stored in
/home/xc_vm/migrations/(src/migrations/in the source repository). -
Each file is named with a sequential number prefix, for example:
001_drop_watch_folders_plex_token.sql
002_panel_logs_add_file_env.sql
003_drop_settings_segment_type.sql
-
Applied DB update steps are tracked in the
migrationsdatabase table. Each step runs exactly once — if a step has already been applied, it is skipped. There is no down/rollback path: migrations are forward-only, so keep them backward-compatible where possible. -
DB updates are executed automatically by:
console.php update post-update— after a panel updateconsole.php status— during system status check (MAIN server only)
Core logic lives in MigrationRunner (src/Core/Database/MigrationRunner.php).
DB Update Execution Flow¶
[ MigrationRunner::run() — DB update execution ]
│
▼
[ CREATE TABLE IF NOT EXISTS `migrations` ]
│
▼
[ Read all *.sql files from migrations/ ]
│
▼
[ For each file not in `migrations` table: ]
├── Execute SQL statements
├── Record in `migrations` table
└── Output [OK] (recorded) or [FAIL] (not recorded)
Creating a New DB Update Step¶
When you need to modify the database schema (add columns, create tables, insert data, etc.), create a new SQL file for a DB update step.
Step 1. Choose a File Name¶
Use the next sequential number and a descriptive name:
Format rules:
- Number prefix: 3 digits, zero-padded (e.g.,
006,007) - Separator: underscore
_ - Name: lowercase, underscores, describing what the update step does
- Extension:
.sql
Examples:
Step 2. Write the SQL¶
Place raw SQL statements in the file. Multiple statements are separated by ;.
Rules for SQL DB update steps:
- Use
IF EXISTS/IF NOT EXISTSto make DB update steps idempotent:
-- Adding a column (safe)
ALTER TABLE `settings` ADD COLUMN IF NOT EXISTS `timezone` VARCHAR(64) DEFAULT 'UTC';
-- Dropping a column (safe)
ALTER TABLE `settings` DROP COLUMN IF EXISTS `old_column`;
-- Creating a table (safe)
CREATE TABLE IF NOT EXISTS `audit_log` (
`id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
`action` VARCHAR(255) NOT NULL,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- Use conditional
INSERTto avoid duplicates:
INSERT INTO `streams_arguments` (argument_key, argument_name, argument_cmd)
SELECT 'my_key', 'My Argument', '-my_flag %s'
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM `streams_arguments` WHERE argument_key = 'my_key');
-
Do not mix DDL and DML that depend on each other in the same file. If you need to add a column and then populate it, use two DB update step files.
-
Comments are supported with
--prefix (they are skipped during execution).
Idempotency matters because a failed step is not recorded — it prints
[FAIL] <name> (not recorded — will retry on next run)and re-runs on the nextdb:migrate. A non-idempotent step that half-applied before failing will be retried from the top, so every statement must be safe to run again (useIF NOT EXISTS,INSERT ... ON DUPLICATE KEY UPDATE, etc.).
Step 3. Place the File¶
Copy the SQL file for the DB update step to:
💡 In the source repository, this is
src/migrations/.
Step 4. Validate DB Update¶
Run db:migrate to apply pending DB update steps:
Or via status first-run (also runs migrations):
Expected output:
If a statement fails, the step prints [FAIL] and is not recorded — so it will be retried on the next run. Review the SQL, fix it, and re-run db:migrate.
Applying Migrations Manually¶
Apply all pending .sql files from /home/xc_vm/migrations/ without a full system update:
Data migration from another system¶
Transfer data from the staging database xc_vm_migrate:
See the Database Update Guide for details.
Related files¶
| File | Role |
|---|---|
src/migrations/ |
Database migration .sql files |
src/Core/Database/MigrationRunner.php |
Executes pending migrations, records the migrations table |
src/console.php |
db:migrate / status / migrate entry point |