or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdconfiguration.mdcore-operations.mdfield-types.mdglobal-operations.mdindex.mdpreferences.mdversion-control.md

version-control.mddocs/

0

# Version Control

1

2

Document versioning system for tracking changes and restoring previous versions of content. Payload's versioning system provides comprehensive audit trails and rollback capabilities for both collections and globals.

3

4

## Capabilities

5

6

### Collection Version Operations

7

8

Version management for collection documents with full history tracking.

9

10

```typescript { .api }

11

/**

12

* Find versions of collection documents with criteria

13

* @param options - Find versions options including collection and query parameters

14

* @returns Promise resolving to paginated versions

15

*/

16

function findVersions<T>(options: FindVersionsOptions): Promise<PaginatedDocs<T>>;

17

18

/**

19

* Find a specific version by ID

20

* @param options - Find version by ID options

21

* @returns Promise resolving to the version document

22

*/

23

function findVersionByID<T>(options: FindVersionByIDOptions): Promise<T>;

24

25

/**

26

* Restore a specific version as the current document

27

* @param options - Restore version options

28

* @returns Promise resolving to the restored document

29

*/

30

function restoreVersion<T>(options: RestoreVersionOptions): Promise<T>;

31

32

interface FindVersionsOptions {

33

/** The collection slug */

34

collection: string;

35

/** Query conditions for versions */

36

where?: Where;

37

/** Sort field and direction */

38

sort?: string;

39

/** Maximum number of versions to return */

40

limit?: number;

41

/** Page number for pagination */

42

page?: number;

43

/** How many levels deep to populate relationships */

44

depth?: number;

45

/** Locale for the operation */

46

locale?: string;

47

/** Fallback locale */

48

fallbackLocale?: string;

49

/** User context for access control */

50

user?: User;

51

/** Whether to override access control */

52

overrideAccess?: boolean;

53

/** Whether to include hidden fields */

54

showHiddenFields?: boolean;

55

}

56

57

interface FindVersionByIDOptions {

58

/** The collection slug */

59

collection: string;

60

/** Version ID to find */

61

id: string | number;

62

/** How many levels deep to populate relationships */

63

depth?: number;

64

/** Locale for the operation */

65

locale?: string;

66

/** Fallback locale */

67

fallbackLocale?: string;

68

/** User context for access control */

69

user?: User;

70

/** Whether to override access control */

71

overrideAccess?: boolean;

72

/** Whether to include hidden fields */

73

showHiddenFields?: boolean;

74

}

75

76

interface RestoreVersionOptions {

77

/** The collection slug */

78

collection: string;

79

/** Version ID to restore */

80

id: string | number;

81

/** How many levels deep to populate relationships in response */

82

depth?: number;

83

/** Locale for the operation */

84

locale?: string;

85

/** Fallback locale */

86

fallbackLocale?: string;

87

/** User context for access control */

88

user?: User;

89

/** Whether to override access control */

90

overrideAccess?: boolean;

91

/** Whether to include hidden fields */

92

showHiddenFields?: boolean;

93

}

94

```

95

96

**Collection Version Examples:**

97

98

```typescript

99

import payload from "payload";

100

101

// Find all versions of a specific post

102

const postVersions = await payload.findVersions({

103

collection: "posts",

104

where: {

105

parent: {

106

equals: postId,

107

},

108

},

109

sort: "-createdAt",

110

limit: 10,

111

});

112

113

console.log(`Found ${postVersions.totalDocs} versions`);

114

postVersions.docs.forEach((version) => {

115

console.log(`Version ${version.id}: ${version.version.title} (${version.createdAt})`);

116

});

117

118

// Find versions with specific criteria

119

const publishedVersions = await payload.findVersions({

120

collection: "posts",

121

where: {

122

and: [

123

{

124

parent: {

125

equals: postId,

126

},

127

},

128

{

129

"version.status": {

130

equals: "published",

131

},

132

},

133

],

134

},

135

});

136

137

// Get a specific version by ID

138

const specificVersion = await payload.findVersionByID({

139

collection: "posts",

140

id: versionId,

141

depth: 1, // Populate relationships in the version

142

});

143

144

console.log("Version content:", specificVersion.version);

145

146

// Restore a previous version

147

const restoredPost = await payload.restoreVersion({

148

collection: "posts",

149

id: versionId,

150

depth: 1,

151

});

152

153

console.log("Restored post:", restoredPost.title);

154

console.log("New version created:", restoredPost.id);

155

```

156

157

### Global Version Operations

158

159

Version management for global documents with singleton version tracking.

160

161

```typescript { .api }

162

/**

163

* Find versions of global documents with criteria

164

* @param options - Find global versions options

165

* @returns Promise resolving to paginated global versions

166

*/

167

function findGlobalVersions<T>(options: FindGlobalVersionsOptions): Promise<PaginatedDocs<T>>;

168

169

/**

170

* Find a specific global version by ID

171

* @param options - Find global version by ID options

172

* @returns Promise resolving to the global version

173

*/

174

function findGlobalVersionByID<T>(options: FindGlobalVersionByIDOptions): Promise<T>;

175

176

/**

177

* Restore a specific global version as the current global

178

* @param options - Restore global version options

179

* @returns Promise resolving to the restored global

180

*/

181

function restoreGlobalVersion<T>(options: RestoreGlobalVersionOptions): Promise<T>;

182

183

interface FindGlobalVersionsOptions {

184

/** The global slug */

185

slug: string;

186

/** Query conditions for versions */

187

where?: Where;

188

/** Sort field and direction */

189

sort?: string;

190

/** Maximum number of versions to return */

191

limit?: number;

192

/** Page number for pagination */

193

page?: number;

194

/** How many levels deep to populate relationships */

195

depth?: number;

196

/** Locale for the operation */

197

locale?: string;

198

/** Fallback locale */

199

fallbackLocale?: string;

200

/** User context for access control */

201

user?: User;

202

/** Whether to override access control */

203

overrideAccess?: boolean;

204

/** Whether to include hidden fields */

205

showHiddenFields?: boolean;

206

}

207

208

interface FindGlobalVersionByIDOptions {

209

/** The global slug */

210

slug: string;

211

/** Version ID to find */

212

id: string | number;

213

/** How many levels deep to populate relationships */

214

depth?: number;

215

/** Locale for the operation */

216

locale?: string;

217

/** Fallback locale */

218

fallbackLocale?: string;

219

/** User context for access control */

220

user?: User;

221

/** Whether to override access control */

222

overrideAccess?: boolean;

223

/** Whether to include hidden fields */

224

showHiddenFields?: boolean;

225

}

226

227

interface RestoreGlobalVersionOptions {

228

/** The global slug */

229

slug: string;

230

/** Version ID to restore */

231

id: string | number;

232

/** How many levels deep to populate relationships in response */

233

depth?: number;

234

/** Locale for the operation */

235

locale?: string;

236

/** Fallback locale */

237

fallbackLocale?: string;

238

/** User context for access control */

239

user?: User;

240

/** Whether to override access control */

241

overrideAccess?: boolean;

242

/** Whether to include hidden fields */

243

showHiddenFields?: boolean;

244

}

245

```

246

247

**Global Version Examples:**

248

249

```typescript

250

// Find all versions of site header

251

const headerVersions = await payload.findGlobalVersions({

252

slug: "header",

253

sort: "-createdAt",

254

limit: 20,

255

});

256

257

console.log(`Header has ${headerVersions.totalDocs} versions`);

258

259

// Find specific version of global

260

const headerVersion = await payload.findGlobalVersionByID({

261

slug: "header",

262

id: versionId,

263

depth: 1,

264

});

265

266

console.log("Version data:", headerVersion.version);

267

268

// Restore a previous header version

269

const restoredHeader = await payload.restoreGlobalVersion({

270

slug: "header",

271

id: versionId,

272

});

273

274

console.log("Header restored to:", restoredHeader.version.title);

275

276

// Find versions by date range

277

const recentVersions = await payload.findGlobalVersions({

278

slug: "siteSettings",

279

where: {

280

createdAt: {

281

greater_than: "2023-01-01T00:00:00.000Z",

282

},

283

},

284

sort: "-createdAt",

285

});

286

```

287

288

## Version Configuration

289

290

### Collection Versioning Setup

291

292

Configure versioning for collections to enable version tracking.

293

294

```typescript { .api }

295

interface CollectionConfig {

296

slug: string;

297

fields: Field[];

298

/** Version configuration */

299

versions?: VersionsConfig | boolean;

300

// ... other options

301

}

302

303

interface VersionsConfig {

304

/** Maximum versions to keep per document (default: unlimited) */

305

maxPerDoc?: number;

306

/** Enable draft versions */

307

drafts?: DraftsConfig | boolean;

308

/** Custom version access control */

309

access?: {

310

read?: AccessFunction;

311

create?: AccessFunction;

312

update?: AccessFunction;

313

delete?: AccessFunction;

314

};

315

}

316

317

interface DraftsConfig {

318

/** Enable autosave for drafts */

319

autosave?: boolean | {

320

/** Autosave interval in milliseconds */

321

interval?: number;

322

};

323

/** Validate drafts on save */

324

validate?: boolean;

325

}

326

```

327

328

**Version Configuration Examples:**

329

330

```typescript

331

// Basic versioning

332

const PostsCollection: CollectionConfig = {

333

slug: "posts",

334

fields: [

335

{

336

name: "title",

337

type: "text",

338

required: true,

339

},

340

{

341

name: "content",

342

type: "richText",

343

},

344

],

345

versions: true, // Enable basic versioning

346

};

347

348

// Advanced versioning with drafts

349

const ArticlesCollection: CollectionConfig = {

350

slug: "articles",

351

fields: [

352

// ... fields

353

],

354

versions: {

355

maxPerDoc: 50, // Keep maximum 50 versions per document

356

drafts: {

357

autosave: {

358

interval: 30000, // Autosave every 30 seconds

359

},

360

validate: false, // Don't validate drafts

361

},

362

},

363

};

364

365

// Version access control

366

const PagesCollection: CollectionConfig = {

367

slug: "pages",

368

fields: [

369

// ... fields

370

],

371

versions: {

372

maxPerDoc: 25,

373

access: {

374

read: ({ req: { user } }) => !!user, // Only authenticated users can view versions

375

create: ({ req: { user } }) => user?.role === "editor",

376

update: ({ req: { user } }) => user?.role === "admin",

377

delete: ({ req: { user } }) => user?.role === "admin",

378

},

379

drafts: true,

380

},

381

};

382

```

383

384

### Global Versioning Setup

385

386

Configure versioning for globals to track changes over time.

387

388

```typescript { .api }

389

interface GlobalConfig {

390

slug: string;

391

fields: Field[];

392

/** Version configuration */

393

versions?: VersionsConfig | boolean;

394

// ... other options

395

}

396

```

397

398

**Global Version Configuration Examples:**

399

400

```typescript

401

// Header global with versioning

402

const HeaderGlobal: GlobalConfig = {

403

slug: "header",

404

label: "Site Header",

405

fields: [

406

{

407

name: "title",

408

type: "text",

409

required: true,

410

},

411

{

412

name: "navigation",

413

type: "array",

414

fields: [

415

{

416

name: "label",

417

type: "text",

418

required: true,

419

},

420

{

421

name: "url",

422

type: "text",

423

required: true,

424

},

425

],

426

},

427

],

428

versions: {

429

maxPerDoc: 100, // Keep 100 versions of header changes

430

drafts: {

431

autosave: true, // Enable autosave for header changes

432

},

433

},

434

};

435

436

// Site settings with controlled versioning

437

const SiteSettingsGlobal: GlobalConfig = {

438

slug: "siteSettings",

439

label: "Site Settings",

440

fields: [

441

// ... fields

442

],

443

versions: {

444

maxPerDoc: 20,

445

access: {

446

read: ({ req: { user } }) => user?.role === "admin",

447

create: ({ req: { user } }) => user?.role === "admin",

448

delete: ({ req: { user } }) => user?.role === "super-admin",

449

},

450

drafts: false, // No drafts for settings

451

},

452

};

453

```

454

455

## Version Data Structure

456

457

### Version Document Structure

458

459

Version documents contain metadata and the versioned content.

460

461

```typescript { .api }

462

interface TypeWithVersion<T> extends TypeWithID {

463

/** The versioned document data */

464

version: T;

465

/** Reference to the parent document */

466

parent: string | TypeWithID;

467

/** Version creation timestamp */

468

createdAt: string;

469

/** Version update timestamp */

470

updatedAt: string;

471

/** User who created this version */

472

createdBy?: User;

473

/** User who last updated this version */

474

updatedBy?: User;

475

/** Whether this is a draft version */

476

draft?: boolean;

477

/** Whether this version is published */

478

published?: boolean;

479

/** Snapshot data at time of version creation */

480

snapshot?: {

481

/** Document data at version creation */

482

data: T;

483

/** Related documents at version creation */

484

relations?: any[];

485

};

486

}

487

```

488

489

## Version Management Examples

490

491

### Version History UI

492

493

```typescript

494

// Get version history for admin UI

495

async function getVersionHistory(collection: string, documentId: string) {

496

const versions = await payload.findVersions({

497

collection,

498

where: {

499

parent: {

500

equals: documentId,

501

},

502

},

503

sort: "-createdAt",

504

limit: 50,

505

depth: 0, // Don't populate for list view

506

});

507

508

return versions.docs.map((version) => ({

509

id: version.id,

510

createdAt: version.createdAt,

511

createdBy: version.createdBy,

512

draft: version.draft,

513

published: version.published,

514

// Add preview data

515

title: version.version.title,

516

status: version.version.status,

517

}));

518

}

519

520

// Compare two versions

521

async function compareVersions(collection: string, versionId1: string, versionId2: string) {

522

const [version1, version2] = await Promise.all([

523

payload.findVersionByID({ collection, id: versionId1 }),

524

payload.findVersionByID({ collection, id: versionId2 }),

525

]);

526

527

return {

528

version1: version1.version,

529

version2: version2.version,

530

metadata: {

531

version1: {

532

createdAt: version1.createdAt,

533

createdBy: version1.createdBy,

534

},

535

version2: {

536

createdAt: version2.createdAt,

537

createdBy: version2.createdBy,

538

},

539

},

540

};

541

}

542

543

// Bulk version cleanup

544

async function cleanupOldVersions(collection: string, keepCount: number = 10) {

545

const documents = await payload.find({

546

collection,

547

limit: 1000,

548

depth: 0,

549

});

550

551

for (const doc of documents.docs) {

552

const versions = await payload.findVersions({

553

collection,

554

where: {

555

parent: {

556

equals: doc.id,

557

},

558

},

559

sort: "-createdAt",

560

limit: 1000,

561

});

562

563

// Delete versions beyond keep count

564

const versionsToDelete = versions.docs.slice(keepCount);

565

566

for (const version of versionsToDelete) {

567

await payload.delete({

568

collection: `_${collection}_versions`,

569

id: version.id,

570

});

571

}

572

}

573

}

574

```

575

576

### Automated Version Management

577

578

```typescript

579

// Collection hook for automatic version creation

580

const PostsCollection: CollectionConfig = {

581

slug: "posts",

582

fields: [

583

// ... fields

584

],

585

versions: {

586

maxPerDoc: 25,

587

drafts: true,

588

},

589

hooks: {

590

beforeChange: [

591

({ data, operation, originalDoc, req }) => {

592

// Add version metadata

593

if (operation === "update") {

594

data._versionNote = `Updated by ${req.user.email} on ${new Date().toISOString()}`;

595

}

596

return data;

597

},

598

],

599

afterChange: [

600

async ({ doc, operation, req }) => {

601

// Notify on version creation

602

if (operation === "update") {

603

req.payload.logger.info(`New version created for post: ${doc.title}`);

604

605

// Send notification email

606

await req.payload.sendEmail({

607

to: "editors@mysite.com",

608

subject: `Post Updated: ${doc.title}`,

609

html: `<p>A new version of "${doc.title}" has been created.</p>`,

610

});

611

}

612

},

613

],

614

},

615

};

616

```