Migrations let you evolve your database schema over time. Each migration has an up (apply) and down (rollback) function, and Prism tracks which migrations have been applied in a _prism_migrations table.
let migrations = [ PrismMigration( version: 1, name: "create_users", up: { db in try db.execute(""" CREATE TABLE users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, email TEXT UNIQUE NOT NULL, created_at TEXT DEFAULT CURRENT_TIMESTAMP ) """) }, down: { db in try db.execute("DROP TABLE IF EXISTS users") } ), PrismMigration( version: 2, name: "create_posts", up: { db in try db.execute(""" CREATE TABLE posts ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, title TEXT NOT NULL, body TEXT, published INTEGER DEFAULT 0, created_at TEXT DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) ) """) }, down: { db in try db.execute("DROP TABLE IF EXISTS posts") } ), PrismMigration( version: 3, name: "add_user_avatar", up: { db in try db.execute("ALTER TABLE users ADD COLUMN avatar_url TEXT") }, down: { db in // SQLite doesn't support DROP COLUMN before 3.35.0 // For older versions, you'd recreate the table } )]
// 1. Define the migrationlet addComments = PrismMigration( version: 4, name: "create_comments", up: { db in try db.execute(""" CREATE TABLE comments ( id INTEGER PRIMARY KEY AUTOINCREMENT, post_id INTEGER NOT NULL, user_id INTEGER NOT NULL, body TEXT NOT NULL, created_at TEXT DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(id) ) """) try db.execute("CREATE INDEX idx_comments_post ON comments(post_id)") }, down: { db in try db.execute("DROP INDEX IF EXISTS idx_comments_post") try db.execute("DROP TABLE IF EXISTS comments") })// 2. Add it to your migrations arraylet migrations = [createUsers, createPosts, addAvatar, addComments]// 3. Run on startuplet migrator = PrismMigrator(database: db, migrations: migrations)try await migrator.migrate()
@mainstruct App { static func main() async throws { let db = try PrismDatabase(path: "app.db") // Run migrations before starting the server let migrator = PrismMigrator(database: db, migrations: allMigrations) try await migrator.migrate() let server = PrismHTTPServer(port: 8080) // ... register routes ... try await server.start() }}
Keep migration version numbers sequential and never modify a migration that’s already been applied in production. Instead, create a new migration to make changes.