Database migrations
TorrentPier uses Phinx for database migrations. This guide covers how to run and create migrations.
Running migrations
Check migration status
See which migrations have been applied:
php vendor/bin/phinx status -c phinx.php
Run pending migrations
Apply all pending migrations:
php vendor/bin/phinx migrate -c phinx.php
Run specific migration
Migrate to a specific version:
php vendor/bin/phinx migrate -c phinx.php -t 20250619000001
Rollback migrations
Rollback the last migration:
php vendor/bin/phinx rollback -c phinx.php
Rollback to a specific version:
php vendor/bin/phinx rollback -c phinx.php -t 20250619000001
For existing installations
If you're upgrading an existing TorrentPier installation, you may need to mark migrations as already applied:
php vendor/bin/phinx migrate -c phinx.php --fake
This records the migrations as applied without actually running them.
Creating migrations
Generate a new migration
php vendor/bin/phinx create MyNewMigration -c phinx.php
This creates a file in database/migrations/ with a timestamp prefix.
Migration structure
<?php
use Phinx\Migration\AbstractMigration;
final class MyNewMigration extends AbstractMigration
{
public function up(): void
{
// Apply changes
$this->table('my_table')
->addColumn('name', 'string', ['limit' => 255])
->addColumn('created_at', 'datetime')
->addIndex(['name'])
->create();
}
public function down(): void
{
// Reverse changes
$this->table('my_table')->drop()->save();
}
}
Common operations
Create table
$this->table('users')
->addColumn('username', 'string', ['limit' => 50])
->addColumn('email', 'string', ['limit' => 100])
->addColumn('created_at', 'datetime')
->addIndex(['username'], ['unique' => true])
->addIndex(['email'], ['unique' => true])
->create();
Modify table
$this->table('users')
->addColumn('avatar', 'string', ['limit' => 255, 'null' => true])
->changeColumn('email', 'string', ['limit' => 150])
->removeColumn('old_column')
->update();
Add foreign key
$this->table('posts')
->addColumn('user_id', 'integer')
->addForeignKey('user_id', 'users', 'id', [
'delete' => 'CASCADE',
'update' => 'NO_ACTION'
])
->create();
Raw SQL
$this->execute('ALTER TABLE users ADD FULLTEXT INDEX (username, email)');
Seed data
Run seeders
php vendor/bin/phinx seed:run -c phinx.php
Run specific seeder
php vendor/bin/phinx seed:run -c phinx.php -s UserSeeder
Configuration
Migration settings are in phinx.php:
return [
'paths' => [
'migrations' => 'database/migrations',
'seeds' => 'database/migrations/seeds'
],
'environments' => [
'default_migration_table' => 'phinxlog',
'default_environment' => 'production',
'production' => [
'adapter' => 'mysql',
'host' => getenv('DB_HOST'),
'name' => getenv('DB_DATABASE'),
'user' => getenv('DB_USERNAME'),
'pass' => getenv('DB_PASSWORD'),
'charset' => 'utf8mb4',
]
]
];
Best practices
- Always test migrations on a copy of production data before deploying
- Write reversible migrations with proper
down()methods - Keep migrations small — one logical change per migration
- Never modify existing migrations that have been applied to production
- Use timestamps in migration names for proper ordering