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

configuration.mddocs/

0

# Configuration System

1

2

Comprehensive configuration system for defining collections, globals, fields, authentication, and admin settings. The configuration serves as the foundation for your entire Payload CMS setup.

3

4

## Capabilities

5

6

### Configuration Builder

7

8

Core function for building and validating Payload configuration with plugin support.

9

10

```typescript { .api }

11

/**

12

* Builds and validates Payload configuration with plugin processing

13

* @param config - The Payload configuration object

14

* @returns Sanitized and validated configuration

15

*/

16

function buildConfig(config: Config): SanitizedConfig;

17

18

/**

19

* Plugin function type for extending Payload functionality

20

*/

21

type Plugin = (config: Config) => Config;

22

```

23

24

**Usage Examples:**

25

26

```typescript

27

import { buildConfig } from "payload/config";

28

29

const config = buildConfig({

30

collections: [

31

// your collections

32

],

33

globals: [

34

// your globals

35

],

36

plugins: [

37

// plugin functions that modify config

38

myCustomPlugin(),

39

anotherPlugin(options),

40

],

41

// ... other config options

42

});

43

44

// Plugin example

45

function myCustomPlugin(): Plugin {

46

return (config: Config) => {

47

// Modify and return config

48

return {

49

...config,

50

// Add custom collections, modify existing config, etc.

51

};

52

};

53

}

54

```

55

56

### Main Configuration

57

58

The primary configuration object that defines your entire Payload setup.

59

60

```typescript { .api }

61

/**

62

* Main Payload configuration interface

63

*/

64

interface Config {

65

/** Base URL for your server (required for emails and admin) */

66

serverURL?: string;

67

/** Array of collection configurations */

68

collections?: CollectionConfig[];

69

/** Array of global configurations */

70

globals?: GlobalConfig[];

71

/** Admin panel configuration */

72

admin?: AdminConfig;

73

/** Authentication configuration */

74

auth?: AuthConfig;

75

/** Email service configuration */

76

email?: EmailConfig;

77

/** File upload configuration */

78

upload?: UploadConfig;

79

/** Internationalization configuration */

80

localization?: LocalizationConfig;

81

/** TypeScript configuration */

82

typescript?: TypeScriptConfig;

83

/** GraphQL configuration */

84

graphQL?: GraphQLConfig;

85

/** CORS configuration */

86

cors?: CORSConfig;

87

/** CSRF protection configuration */

88

csrf?: CSRFConfig;

89

/** Express configuration */

90

express?: ExpressConfig;

91

/** API route configuration */

92

routes?: {

93

/** Admin panel route (default: "/admin") */

94

admin?: string;

95

/** API base route (default: "/api") */

96

api?: string;

97

/** GraphQL endpoint (default: "/api/graphql") */

98

graphQL?: string;

99

/** GraphQL playground route (default: "/api/graphql-playground") */

100

graphQLPlayground?: string;

101

};

102

/** Rate limiting configuration */

103

rateLimit?: RateLimitConfig;

104

/** Global hooks */

105

hooks?: {

106

/** Hook called after errors occur */

107

afterError?: AfterErrorHook;

108

};

109

/** Enable/disable telemetry */

110

telemetry?: boolean;

111

/** Enable debug mode */

112

debug?: boolean;

113

/** Logger configuration */

114

loggerOptions?: LoggerOptions;

115

}

116

```

117

118

**Basic Configuration Example:**

119

120

```typescript

121

import { Config } from "payload/config";

122

123

const config: Config = {

124

serverURL: "http://localhost:3000",

125

collections: [

126

{

127

slug: "posts",

128

fields: [

129

{

130

name: "title",

131

type: "text",

132

required: true,

133

},

134

{

135

name: "content",

136

type: "richText",

137

},

138

],

139

},

140

],

141

globals: [

142

{

143

slug: "header",

144

fields: [

145

{

146

name: "title",

147

type: "text",

148

},

149

],

150

},

151

],

152

};

153

154

export default config;

155

```

156

157

### Custom Endpoints

158

159

Configuration for custom REST API endpoints that extend Payload's built-in API.

160

161

```typescript { .api }

162

/**

163

* Custom endpoint configuration

164

*/

165

interface Endpoint {

166

/** URL path for the endpoint */

167

path: string;

168

/** HTTP method */

169

method: 'get' | 'head' | 'post' | 'put' | 'patch' | 'delete' | 'connect' | 'options' | string;

170

/** Handler function(s) for the endpoint */

171

handler: PayloadHandler | PayloadHandler[];

172

}

173

174

/**

175

* Payload request handler function

176

*/

177

interface PayloadHandler {

178

(req: PayloadRequest, res: Response, next: NextFunction): void;

179

}

180

```

181

182

**Usage Examples:**

183

184

```typescript

185

const config: Config = {

186

// ... other config

187

endpoints: [

188

{

189

path: '/custom-api',

190

method: 'get',

191

handler: (req, res, next) => {

192

res.json({ message: 'Custom endpoint' });

193

},

194

},

195

{

196

path: '/webhook',

197

method: 'post',

198

handler: [

199

// Multiple handlers can be used

200

authMiddleware,

201

webhookHandler,

202

],

203

},

204

],

205

};

206

```

207

208

### Admin Panel Customization

209

210

Configuration for custom admin panel routes and components.

211

212

```typescript { .api }

213

/**

214

* Custom admin view component type

215

*/

216

type AdminView = React.ComponentType<{

217

user: User;

218

canAccessAdmin: boolean;

219

}>;

220

221

/**

222

* Custom admin route configuration

223

*/

224

interface AdminRoute {

225

/** React component to render */

226

Component: AdminView;

227

/** URL path for the route */

228

path: string;

229

/** Exact path matching (default: false) */

230

exact?: boolean;

231

/** Strict path matching (default: false) */

232

strict?: boolean;

233

}

234

```

235

236

**Usage Examples:**

237

238

```typescript

239

import CustomDashboard from './CustomDashboard';

240

import AnalyticsView from './AnalyticsView';

241

242

const config: Config = {

243

// ... other config

244

admin: {

245

// ... other admin config

246

routes: [

247

{

248

Component: CustomDashboard,

249

path: '/custom-dashboard',

250

exact: true,

251

},

252

{

253

Component: AnalyticsView,

254

path: '/analytics',

255

},

256

],

257

},

258

};

259

```

260

261

### Collection Configuration

262

263

Configuration for content collections (e.g., posts, products, users).

264

265

```typescript { .api }

266

interface CollectionConfig {

267

/** Unique identifier for the collection */

268

slug: string;

269

/** Array of field configurations */

270

fields: Field[];

271

/** Display labels for the collection */

272

labels?: {

273

singular?: string;

274

plural?: string;

275

};

276

/** Admin panel configuration */

277

admin?: CollectionAdminConfig;

278

/** Authentication configuration (makes collection auth-enabled) */

279

auth?: AuthConfig | boolean;

280

/** Access control rules */

281

access?: CollectionAccessConfig;

282

/** Collection-level hooks */

283

hooks?: CollectionHooks;

284

/** File upload configuration */

285

upload?: UploadConfig | boolean;

286

/** Document versioning configuration */

287

versions?: VersionsConfig | boolean;

288

/** Automatic timestamp fields */

289

timestamps?: boolean;

290

/** Database collection name override */

291

dbName?: string;

292

/** Default sort field */

293

defaultSort?: string;

294

/** Disable duplicate checking */

295

disableDuplicate?: boolean;

296

/** GraphQL configuration */

297

graphQL?: {

298

singularName?: string;

299

pluralName?: string;

300

};

301

/** TypeScript configuration */

302

typescript?: {

303

interface?: string;

304

};

305

}

306

307

interface CollectionAdminConfig {

308

/** Default columns to show in list view */

309

defaultColumns?: string[];

310

/** Description shown in admin */

311

description?: string;

312

/** Fields to use for document preview */

313

useAsTitle?: string;

314

/** Custom pagination limit */

315

pagination?: {

316

defaultLimit?: number;

317

limits?: number[];

318

};

319

/** List view configuration */

320

listSearchableFields?: string[];

321

/** Group collections in admin sidebar */

322

group?: string;

323

/** Hide collection from admin */

324

hidden?: boolean;

325

/** Disable create operation in admin */

326

disableCreate?: boolean;

327

/** Disable edit operation in admin */

328

disableEdit?: boolean;

329

/** Disable delete operation in admin */

330

disableDelete?: boolean;

331

/** Custom admin components */

332

components?: {

333

Edit?: React.ComponentType;

334

List?: React.ComponentType;

335

};

336

}

337

```

338

339

**Collection Configuration Example:**

340

341

```typescript

342

const PostsCollection: CollectionConfig = {

343

slug: "posts",

344

labels: {

345

singular: "Post",

346

plural: "Posts",

347

},

348

admin: {

349

defaultColumns: ["title", "status", "createdAt"],

350

useAsTitle: "title",

351

description: "Blog posts and articles",

352

group: "Content",

353

},

354

access: {

355

read: () => true,

356

create: ({ req: { user } }) => !!user,

357

update: ({ req: { user } }) => !!user,

358

delete: ({ req: { user } }) => !!user,

359

},

360

fields: [

361

{

362

name: "title",

363

type: "text",

364

required: true,

365

},

366

{

367

name: "content",

368

type: "richText",

369

required: true,

370

},

371

{

372

name: "status",

373

type: "select",

374

options: [

375

{ label: "Draft", value: "draft" },

376

{ label: "Published", value: "published" },

377

],

378

defaultValue: "draft",

379

},

380

],

381

hooks: {

382

beforeChange: [

383

({ data, operation }) => {

384

if (operation === "create") {

385

data.createdBy = req.user.id;

386

}

387

return data;

388

},

389

],

390

},

391

versions: {

392

drafts: true,

393

maxPerDoc: 10,

394

},

395

timestamps: true,

396

};

397

```

398

399

### Global Configuration

400

401

Configuration for global documents (singleton content like site settings).

402

403

```typescript { .api }

404

interface GlobalConfig {

405

/** Unique identifier for the global */

406

slug: string;

407

/** Array of field configurations */

408

fields: Field[];

409

/** Display label for the global */

410

label?: string;

411

/** Admin panel configuration */

412

admin?: GlobalAdminConfig;

413

/** Access control rules */

414

access?: GlobalAccessConfig;

415

/** Global-level hooks */

416

hooks?: GlobalHooks;

417

/** Document versioning configuration */

418

versions?: VersionsConfig | boolean;

419

/** Automatic timestamp fields */

420

timestamps?: boolean;

421

/** Database collection name override */

422

dbName?: string;

423

/** GraphQL configuration */

424

graphQL?: {

425

name?: string;

426

};

427

/** TypeScript configuration */

428

typescript?: {

429

interface?: string;

430

};

431

}

432

433

interface GlobalAdminConfig {

434

/** Description shown in admin */

435

description?: string;

436

/** Group globals in admin sidebar */

437

group?: string;

438

/** Hide global from admin */

439

hidden?: boolean;

440

/** Custom admin components */

441

components?: {

442

Edit?: React.ComponentType;

443

};

444

}

445

```

446

447

**Global Configuration Example:**

448

449

```typescript

450

const HeaderGlobal: GlobalConfig = {

451

slug: "header",

452

label: "Site Header",

453

admin: {

454

description: "Configure the site header content",

455

group: "Layout",

456

},

457

access: {

458

read: () => true,

459

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

460

},

461

fields: [

462

{

463

name: "logo",

464

type: "upload",

465

relationTo: "media",

466

},

467

{

468

name: "navigation",

469

type: "array",

470

fields: [

471

{

472

name: "label",

473

type: "text",

474

required: true,

475

},

476

{

477

name: "url",

478

type: "text",

479

required: true,

480

},

481

],

482

},

483

],

484

versions: true,

485

};

486

```

487

488

### Access Control Configuration

489

490

Fine-grained access control for collections and globals.

491

492

```typescript { .api }

493

interface CollectionAccessConfig {

494

/** Control who can read documents */

495

read?: AccessFunction;

496

/** Control who can create documents */

497

create?: AccessFunction;

498

/** Control who can update documents */

499

update?: AccessFunction;

500

/** Control who can delete documents */

501

delete?: AccessFunction;

502

/** Control admin panel access */

503

admin?: AccessFunction;

504

}

505

506

interface GlobalAccessConfig {

507

/** Control who can read the global */

508

read?: AccessFunction;

509

/** Control who can update the global */

510

update?: AccessFunction;

511

/** Control admin panel access */

512

admin?: AccessFunction;

513

}

514

515

type AccessFunction = (args: {

516

req: PayloadRequest;

517

data?: any;

518

id?: string;

519

}) => boolean | Promise<boolean> | Where;

520

```

521

522

**Access Control Examples:**

523

524

```typescript

525

// Collection access control

526

const access: CollectionAccessConfig = {

527

// Public read access

528

read: () => true,

529

530

// Only authenticated users can create

531

create: ({ req: { user } }) => !!user,

532

533

// Users can only update their own posts

534

update: ({ req: { user } }) => {

535

if (user?.role === "admin") return true;

536

537

return {

538

author: {

539

equals: user?.id,

540

},

541

};

542

},

543

544

// Only admins can delete

545

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

546

547

// Admin access based on role

548

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

549

};

550

551

// Field-level access control

552

const titleField: Field = {

553

name: "title",

554

type: "text",

555

access: {

556

read: () => true,

557

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

558

},

559

};

560

```

561

562

### Hooks Configuration

563

564

Collection and global hooks for extending functionality.

565

566

```typescript { .api }

567

interface CollectionHooks {

568

/** Before operation hooks */

569

beforeOperation?: BeforeOperationHook[];

570

/** Before validation hooks */

571

beforeValidate?: BeforeValidateHook[];

572

/** Before change hooks */

573

beforeChange?: BeforeChangeHook[];

574

/** After change hooks */

575

afterChange?: AfterChangeHook[];

576

/** Before read hooks */

577

beforeRead?: BeforeReadHook[];

578

/** After read hooks */

579

afterReadHook?: AfterReadHook[];

580

/** Before delete hooks */

581

beforeDelete?: BeforeDeleteHook[];

582

/** After delete hooks */

583

afterDelete?: AfterDeleteHook[];

584

/** Auth-specific hooks */

585

beforeLogin?: BeforeLoginHook[];

586

afterLogin?: AfterLoginHook[];

587

afterForgotPassword?: AfterForgotPasswordHook[];

588

}

589

590

type BeforeChangeHook = (args: {

591

data: any;

592

req: PayloadRequest;

593

operation: "create" | "update";

594

originalDoc?: any;

595

}) => any | Promise<any>;

596

597

type AfterChangeHook = (args: {

598

doc: any;

599

req: PayloadRequest;

600

previousDoc?: any;

601

operation: "create" | "update";

602

}) => any | Promise<any>;

603

```

604

605

### Admin Configuration

606

607

Admin panel configuration and customization.

608

609

```typescript { .api }

610

interface AdminConfig {

611

/** Custom bundled admin build */

612

bundler?: Bundler;

613

/** Custom CSS file path */

614

css?: string;

615

/** Custom SCSS file path */

616

scss?: string;

617

/** Date display format */

618

dateFormat?: string;

619

/** Disable admin completely */

620

disable?: boolean;

621

/** Custom login logo */

622

logoBg?: string;

623

/** Custom login view */

624

components?: {

625

Nav?: React.ComponentType;

626

Dashboard?: React.ComponentType;

627

logout?: React.ComponentType;

628

};

629

/** Custom admin meta tags */

630

meta?: {

631

titleSuffix?: string;

632

ogImage?: string;

633

favicon?: string;

634

};

635

/** User collection slug for admin authentication */

636

user?: string;

637

/** Avatar configuration */

638

avatar?: "default" | "gravatar" | React.ComponentType;

639

/** Pagination settings */

640

pagination?: {

641

defaultLimit?: number;

642

limits?: number[];

643

};

644

}

645

```

646

647

## Collection Hook System

648

649

### Hook Types

650

651

Comprehensive hook system for extending collection behavior at different lifecycle stages.

652

653

```typescript { .api }

654

/**

655

* Collection hooks configuration

656

*/

657

interface CollectionHooks {

658

/** Before any operation starts */

659

beforeOperation?: BeforeOperationHook[];

660

/** Before data validation */

661

beforeValidate?: BeforeValidateHook[];

662

/** Before data change (create/update) */

663

beforeChange?: BeforeChangeHook[];

664

/** After data change (create/update) */

665

afterChange?: AfterChangeHook[];

666

/** Before document read */

667

beforeRead?: BeforeReadHook[];

668

/** After document read */

669

afterRead?: AfterReadHook[];

670

/** Before document deletion */

671

beforeDelete?: BeforeDeleteHook[];

672

/** After document deletion */

673

afterDelete?: AfterDeleteHook[];

674

/** After operation error */

675

afterError?: AfterErrorHook;

676

/** Before user login (auth collections only) */

677

beforeLogin?: BeforeLoginHook[];

678

/** After user login (auth collections only) */

679

afterLogin?: AfterLoginHook[];

680

/** After user logout (auth collections only) */

681

afterLogout?: AfterLogoutHook[];

682

/** After "me" operation (auth collections only) */

683

afterMe?: AfterMeHook[];

684

/** After token refresh (auth collections only) */

685

afterRefresh?: AfterRefreshHook[];

686

/** After forgot password (auth collections only) */

687

afterForgotPassword?: AfterForgotPasswordHook[];

688

}

689

690

/**

691

* Hook called before any operation

692

*/

693

type BeforeOperationHook = (args: {

694

/** Operation arguments */

695

args?: any;

696

/** Operation type being performed */

697

operation: 'create' | 'read' | 'update' | 'delete' | 'login' | 'refresh' | 'logout' | 'me' | 'forgotPassword' | 'resetPassword';

698

}) => any;

699

700

/**

701

* Hook called before data validation

702

*/

703

type BeforeValidateHook<T = any> = (args: {

704

/** Document data to be validated */

705

data?: Partial<T>;

706

/** Express request object */

707

req?: PayloadRequest;

708

/** Operation type */

709

operation: 'create' | 'update';

710

/** Original document (for updates) */

711

originalDoc?: T;

712

}) => any;

713

714

/**

715

* Hook called before data changes are saved

716

*/

717

type BeforeChangeHook<T = any> = (args: {

718

/** Document data to be saved */

719

data: Partial<T>;

720

/** Express request object */

721

req: PayloadRequest;

722

/** Operation type */

723

operation: 'create' | 'update';

724

/** Original document (for updates) */

725

originalDoc?: T;

726

}) => any;

727

728

/**

729

* Hook called after data changes are saved

730

*/

731

type AfterChangeHook<T = any> = (args: {

732

/** Saved document */

733

doc: T;

734

/** Express request object */

735

req: PayloadRequest;

736

/** Operation type */

737

operation: 'create' | 'update';

738

/** Original document (for updates) */

739

previousDoc?: T;

740

}) => void;

741

742

/**

743

* Hook called before document read

744

*/

745

type BeforeReadHook = (args: {

746

/** Express request object */

747

req: PayloadRequest;

748

/** Query arguments */

749

query?: any;

750

}) => any;

751

752

/**

753

* Hook called after document read

754

*/

755

type AfterReadHook<T = any> = (args: {

756

/** Read document(s) */

757

doc: T | T[];

758

/** Express request object */

759

req: PayloadRequest;

760

/** Query arguments */

761

query?: any;

762

}) => T | T[];

763

764

/**

765

* Hook called before document deletion

766

*/

767

type BeforeDeleteHook<T = any> = (args: {

768

/** Express request object */

769

req: PayloadRequest;

770

/** Document ID being deleted */

771

id: string | number;

772

/** Document being deleted */

773

doc?: T;

774

}) => void;

775

776

/**

777

* Hook called after document deletion

778

*/

779

type AfterDeleteHook<T = any> = (args: {

780

/** Express request object */

781

req: PayloadRequest;

782

/** Document ID that was deleted */

783

id: string | number;

784

/** Document that was deleted */

785

doc: T;

786

}) => void;

787

788

/**

789

* Authentication-specific hooks

790

*/

791

type BeforeLoginHook<T = any> = (args: {

792

/** Express request object */

793

req: PayloadRequest;

794

/** User attempting to login */

795

user: T;

796

}) => void;

797

798

type AfterLoginHook<T = any> = (args: {

799

/** Express request object */

800

req: PayloadRequest;

801

/** Logged in user */

802

user: T;

803

/** JWT token */

804

token: string;

805

}) => void;

806

807

type AfterLogoutHook<T = any> = (args: {

808

/** Express request object */

809

req: PayloadRequest;

810

/** User that logged out */

811

user?: T;

812

}) => void;

813

```

814

815

**Hook Usage Examples:**

816

817

```typescript

818

// Collection with comprehensive hooks

819

const PostsCollection: CollectionConfig = {

820

slug: "posts",

821

hooks: {

822

// Log all operations

823

beforeOperation: [

824

({ args, operation }) => {

825

console.log(`Starting ${operation} operation`, args);

826

return args;

827

},

828

],

829

830

// Auto-populate author field on create

831

beforeChange: [

832

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

833

if (operation === 'create' && req.user) {

834

data.author = req.user.id;

835

data.createdBy = req.user.id;

836

}

837

if (operation === 'update' && req.user) {

838

data.updatedBy = req.user.id;

839

}

840

return data;

841

},

842

],

843

844

// Generate slug from title

845

beforeValidate: [

846

({ data, operation }) => {

847

if ((operation === 'create' || operation === 'update') && data.title && !data.slug) {

848

data.slug = data.title

849

.toLowerCase()

850

.replace(/[^a-z0-9]+/g, '-')

851

.replace(/(^-|-$)/g, '');

852

}

853

return data;

854

},

855

],

856

857

// Clear cache after changes

858

afterChange: [

859

({ doc, operation }) => {

860

console.log(`${operation} completed for post: ${doc.title}`);

861

// Clear cache, send notifications, etc.

862

clearPostCache(doc.id);

863

if (operation === 'create') {

864

sendNewPostNotification(doc);

865

}

866

},

867

],

868

869

// Filter sensitive data from reads

870

afterRead: [

871

({ doc, req }) => {

872

// Remove internal fields for non-admin users

873

if (!req.user || req.user.role !== 'admin') {

874

if (Array.isArray(doc)) {

875

return doc.map(item => ({

876

...item,

877

internalNotes: undefined,

878

adminOnlyField: undefined,

879

}));

880

} else {

881

return {

882

...doc,

883

internalNotes: undefined,

884

adminOnlyField: undefined,

885

};

886

}

887

}

888

return doc;

889

},

890

],

891

892

// Cleanup related data on delete

893

beforeDelete: [

894

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

895

// Delete related comments

896

await req.payload.delete({

897

collection: 'comments',

898

where: {

899

post: {

900

equals: id,

901

},

902

},

903

});

904

905

// Log deletion

906

console.log(`Deleting post: ${doc?.title} (${id})`);

907

},

908

],

909

910

// Post-deletion cleanup

911

afterDelete: [

912

({ req, id, doc }) => {

913

// Clear caches, update search indexes, etc.

914

clearPostCache(id);

915

updateSearchIndex();

916

console.log(`Post deleted: ${doc.title}`);

917

},

918

],

919

920

// Handle errors

921

afterError: (err, args) => {

922

console.error('Collection operation failed:', err);

923

// Send error to monitoring service

924

sendErrorToMonitoring(err, args);

925

return null;

926

},

927

},

928

fields: [

929

{

930

name: "title",

931

type: "text",

932

required: true,

933

},

934

{

935

name: "slug",

936

type: "text",

937

unique: true,

938

},

939

{

940

name: "author",

941

type: "relationship",

942

relationTo: "users",

943

},

944

],

945

};

946

947

// Auth collection with login hooks

948

const UsersCollection: CollectionConfig = {

949

slug: "users",

950

auth: true,

951

hooks: {

952

// Track login attempts

953

beforeLogin: [

954

({ user, req }) => {

955

console.log(`Login attempt for user: ${user.email}`);

956

// Log to analytics, check for suspicious activity, etc.

957

},

958

],

959

960

// Post-login processing

961

afterLogin: [

962

({ user, req, token }) => {

963

console.log(`User logged in: ${user.email}`);

964

// Update last login timestamp, log activity, send welcome email, etc.

965

updateUserActivity(user.id, 'login');

966

},

967

],

968

969

// Cleanup on logout

970

afterLogout: [

971

({ user, req }) => {

972

if (user) {

973

console.log(`User logged out: ${user.email}`);

974

updateUserActivity(user.id, 'logout');

975

}

976

},

977

],

978

},

979

fields: [

980

{

981

name: "firstName",

982

type: "text",

983

required: true,

984

},

985

{

986

name: "lastName",

987

type: "text",

988

required: true,

989

},

990

],

991

};

992

```

993

994

## Environment Configuration

995

996

Environment variables commonly used with Payload configuration.

997

998

```typescript { .api }

999

// Common environment variables

1000

interface EnvironmentVariables {

1001

/** Database connection string */

1002

DATABASE_URI?: string;

1003

/** Payload secret key */

1004

PAYLOAD_SECRET?: string;

1005

/** Server URL */

1006

PAYLOAD_PUBLIC_SERVER_URL?: string;

1007

/** Email service configuration */

1008

SMTP_HOST?: string;

1009

SMTP_PORT?: string;

1010

SMTP_USER?: string;

1011

SMTP_PASS?: string;

1012

/** File upload configuration */

1013

CLOUDINARY_CLOUD_NAME?: string;

1014

CLOUDINARY_API_KEY?: string;

1015

CLOUDINARY_API_SECRET?: string;

1016

/** Node environment */

1017

NODE_ENV?: "development" | "production" | "test";

1018

}

1019

```

1020

1021

**Environment Configuration Example:**

1022

1023

```typescript

1024

const config: Config = {

1025

serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL || "http://localhost:3000",

1026

mongoURL: process.env.DATABASE_URI,

1027

secret: process.env.PAYLOAD_SECRET,

1028

email: {

1029

transport: {

1030

host: process.env.SMTP_HOST,

1031

port: parseInt(process.env.SMTP_PORT),

1032

auth: {

1033

user: process.env.SMTP_USER,

1034

pass: process.env.SMTP_PASS,

1035

},

1036

},

1037

fromName: "My Site",

1038

fromAddress: "noreply@mysite.com",

1039

},

1040

};

1041

```