or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

adapter-configuration.mddrizzle-integration.mdindex.mdmigration-system.md

migration-system.mddocs/

0

# Migration System

1

2

Comprehensive database migration utilities for schema management, data transformations, and production deployments. The migration system provides both automated schema migrations and custom migration support.

3

4

## Capabilities

5

6

### Migration Function Arguments

7

8

Standard arguments provided to all migration functions for database and API access.

9

10

```typescript { .api }

11

interface MigrateUpArgs {

12

/**

13

* The SQLite Drizzle instance for direct SQL execution within current transaction

14

* Provides access to raw SQL execution and Drizzle query builder

15

*/

16

db: Drizzle;

17

/**

18

* The Payload instance for Local API method execution

19

* Use with 'req' parameter to maintain transaction context

20

*/

21

payload: Payload;

22

/**

23

* The PayloadRequest object containing the current transaction

24

* Required for transactional Local API operations

25

*/

26

req: PayloadRequest;

27

}

28

29

interface MigrateDownArgs {

30

/**

31

* The SQLite Drizzle instance for direct SQL execution within current transaction

32

* Provides access to raw SQL execution and Drizzle query builder

33

*/

34

db: Drizzle;

35

/**

36

* The Payload instance for Local API method execution

37

* Use with 'req' parameter to maintain transaction context

38

*/

39

payload: Payload;

40

/**

41

* The PayloadRequest object containing the current transaction

42

* Required for transactional Local API operations

43

*/

44

req: PayloadRequest;

45

}

46

```

47

48

### Production Migrations

49

50

Define custom migration functions for production deployments.

51

52

```typescript { .api }

53

interface ProductionMigration {

54

/** Migration name for tracking and identification */

55

name: string;

56

/** Forward migration function */

57

up: (args: MigrateUpArgs) => Promise<void>;

58

/** Rollback migration function */

59

down: (args: MigrateDownArgs) => Promise<void>;

60

}

61

62

interface ProductionMigrationConfiguration {

63

/** Array of production migration definitions */

64

prodMigrations?: ProductionMigration[];

65

}

66

```

67

68

**Usage Examples:**

69

70

```typescript

71

import { sqliteAdapter, sql } from '@payloadcms/db-sqlite';

72

import type { MigrateUpArgs, MigrateDownArgs } from '@payloadcms/db-sqlite';

73

74

const adapter = sqliteAdapter({

75

client: { url: './payload.db' },

76

prodMigrations: [

77

{

78

name: '20240101_add_user_preferences',

79

async up({ db, payload, req }: MigrateUpArgs) {

80

// Direct SQL execution

81

await db.run(sql`

82

ALTER TABLE users

83

ADD COLUMN preferences TEXT DEFAULT '{}'

84

`);

85

86

// Use Payload Local API within transaction

87

const users = await payload.find({

88

collection: 'users',

89

req, // Pass req to maintain transaction context

90

});

91

92

for (const user of users.docs) {

93

await payload.update({

94

collection: 'users',

95

id: user.id,

96

data: {

97

preferences: JSON.stringify({ theme: 'light' }),

98

},

99

req,

100

});

101

}

102

},

103

async down({ db, payload, req }: MigrateDownArgs) {

104

// Rollback changes

105

await db.run(sql`

106

ALTER TABLE users

107

DROP COLUMN preferences

108

`);

109

},

110

},

111

],

112

});

113

```

114

115

### Migration Directory Configuration

116

117

Configure custom migration directory paths for automated migrations.

118

119

```typescript { .api }

120

interface MigrationDirectoryConfiguration {

121

/** Custom path to migration files directory */

122

migrationDir?: string;

123

}

124

```

125

126

**Usage Examples:**

127

128

```typescript

129

// Default migrations directory (./migrations)

130

const defaultMigrations = sqliteAdapter({

131

client: { url: './payload.db' },

132

// migrationDir not specified - uses default

133

});

134

135

// Custom migrations directory

136

const customMigrations = sqliteAdapter({

137

client: { url: './payload.db' },

138

migrationDir: './database/migrations',

139

});

140

```

141

142

### SQL Template Literal

143

144

Utility for constructing raw SQL queries with proper escaping and parameter binding.

145

146

```typescript { .api }

147

/**

148

* SQL template literal function for safe query construction

149

* Imported from drizzle-orm with proper SQLite dialect support

150

*/

151

declare const sql: <T = unknown>(

152

strings: TemplateStringsArray,

153

...values: any[]

154

) => SQL<T>;

155

```

156

157

**Usage Examples:**

158

159

```typescript

160

import { sql } from '@payloadcms/db-sqlite';

161

162

// Basic migration with raw SQL

163

export async function up({ db }: MigrateUpArgs) {

164

// Create index

165

await db.run(sql`

166

CREATE INDEX idx_users_email

167

ON users(email)

168

`);

169

170

// Insert data with parameters

171

const userData = { name: 'Admin', email: 'admin@example.com' };

172

await db.run(sql`

173

INSERT INTO users (name, email)

174

VALUES (${userData.name}, ${userData.email})

175

`);

176

177

// Complex query with multiple parameters

178

const threshold = 100;

179

const status = 'active';

180

const results = await db.run(sql`

181

UPDATE posts

182

SET status = ${status}

183

WHERE view_count > ${threshold}

184

`);

185

}

186

```

187

188

### Migration File Structure

189

190

Standard structure for migration files in the migrations directory.

191

192

```typescript { .api }

193

/**

194

* Standard migration file exports

195

* Each migration file should export up and down functions

196

*/

197

interface MigrationFile {

198

/** Forward migration function */

199

up: (args: MigrateUpArgs) => Promise<void>;

200

/** Rollback migration function */

201

down: (args: MigrateDownArgs) => Promise<void>;

202

}

203

```

204

205

**Migration File Example:**

206

207

```typescript

208

// migrations/20240101_001_add_user_roles.ts

209

import type { MigrateUpArgs, MigrateDownArgs } from '@payloadcms/db-sqlite';

210

import { sql } from '@payloadcms/db-sqlite';

211

212

export async function up({ db, payload, req }: MigrateUpArgs): Promise<void> {

213

// Create roles table

214

await db.run(sql`

215

CREATE TABLE user_roles (

216

id INTEGER PRIMARY KEY AUTOINCREMENT,

217

user_id INTEGER NOT NULL,

218

role TEXT NOT NULL,

219

created_at DATETIME DEFAULT CURRENT_TIMESTAMP,

220

FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE

221

)

222

`);

223

224

// Migrate existing data using Payload API

225

const users = await payload.find({

226

collection: 'users',

227

req,

228

});

229

230

for (const user of users.docs) {

231

await db.run(sql`

232

INSERT INTO user_roles (user_id, role)

233

VALUES (${user.id}, 'user')

234

`);

235

}

236

}

237

238

export async function down({ db }: MigrateDownArgs): Promise<void> {

239

await db.run(sql`DROP TABLE user_roles`);

240

}

241

```

242

243

### Transaction Context

244

245

All migrations run within database transactions, ensuring data consistency.

246

247

```typescript { .api }

248

/**

249

* Migration execution context

250

* All migration functions run within a database transaction

251

* Transaction is automatically committed on success or rolled back on error

252

*/

253

interface MigrationContext {

254

/** Automatic transaction management */

255

autoTransaction: true;

256

/** Transaction isolation level */

257

isolation: 'READ_COMMITTED';

258

/** Rollback on error */

259

rollbackOnError: true;

260

}

261

```

262

263

**Best Practices:**

264

265

```typescript

266

export async function up({ db, payload, req }: MigrateUpArgs) {

267

try {

268

// All operations are automatically wrapped in a transaction

269

await db.run(sql`ALTER TABLE posts ADD COLUMN featured BOOLEAN DEFAULT FALSE`);

270

271

// Update existing records

272

await db.run(sql`UPDATE posts SET featured = TRUE WHERE view_count > 1000`);

273

274

// Use Payload API (will use same transaction via req)

275

const featuredPosts = await payload.find({

276

collection: 'posts',

277

where: { featured: { equals: true } },

278

req, // Critical: pass req to maintain transaction context

279

});

280

281

console.log(`Updated ${featuredPosts.totalDocs} featured posts`);

282

283

// Transaction commits automatically on success

284

} catch (error) {

285

// Transaction rolls back automatically on error

286

console.error('Migration failed:', error);

287

throw error; // Re-throw to trigger rollback

288

}

289

}

290

```

291

292

### Error Handling

293

294

Proper error handling patterns for migration functions.

295

296

```typescript { .api }

297

/**

298

* Migration error handling

299

* Errors in migration functions trigger automatic transaction rollback

300

*/

301

interface MigrationErrorHandling {

302

/** Automatic rollback on uncaught errors */

303

autoRollback: true;

304

/** Error logging and reporting */

305

errorReporting: boolean;

306

/** Migration status tracking */

307

statusTracking: boolean;

308

}

309

```

310

311

**Error Handling Examples:**

312

313

```typescript

314

export async function up({ db, payload, req }: MigrateUpArgs) {

315

// Validate preconditions

316

const tableExists = await db.get(sql`

317

SELECT name FROM sqlite_master

318

WHERE type='table' AND name='users'

319

`);

320

321

if (!tableExists) {

322

throw new Error('Users table does not exist - cannot proceed with migration');

323

}

324

325

try {

326

// Perform migration operations

327

await db.run(sql`ALTER TABLE users ADD COLUMN last_login DATETIME`);

328

329

// Validate migration success

330

const columnExists = await db.get(sql`

331

PRAGMA table_info(users)

332

`).then(info => info.some(col => col.name === 'last_login'));

333

334

if (!columnExists) {

335

throw new Error('Failed to add last_login column');

336

}

337

338

} catch (error) {

339

// Log detailed error information

340

console.error('Migration failed at step:', error.message);

341

console.error('Stack trace:', error.stack);

342

343

// Re-throw to trigger rollback

344

throw error;

345

}

346

}

347

```