or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

api.mdconcepts.mdindex.mdpages-router.mdpatterns.mdspecial-files.md

pages-router.mddocs/

0

# Pages Router (Legacy)

1

2

Complete reference for Next.js Pages Router with data fetching methods, API routes, and navigation.

3

4

> **Note**: The Pages Router is the legacy routing system. New projects should use the App Router for better performance and features.

5

6

The Pages Router provides traditional file-system based routing with data fetching methods including getStaticProps, getServerSideProps, and API routes for full-stack development.

7

8

## Capabilities

9

10

### useRouter Hook

11

12

Pages Router navigation hook for programmatic routing and accessing route state. Must be used in Client Components.

13

14

```typescript { .api }

15

import { useRouter } from 'next/router';

16

17

/**

18

* Returns the Pages Router instance

19

* @returns NextRouter with navigation methods and route state

20

*/

21

function useRouter(): NextRouter;

22

23

interface NextRouter {

24

/**

25

* The current pathname including dynamic route parameters

26

*/

27

pathname: string;

28

29

/**

30

* The query string parsed as an object, including dynamic route parameters

31

*/

32

query: ParsedUrlQuery;

33

34

/**

35

* The actual path shown in the browser

36

*/

37

asPath: string;

38

39

/**

40

* The base path configured in next.config.js

41

*/

42

basePath: string;

43

44

/**

45

* The active locale

46

*/

47

locale?: string;

48

49

/**

50

* All configured locales

51

*/

52

locales?: string[];

53

54

/**

55

* The default locale

56

*/

57

defaultLocale?: string;

58

59

/**

60

* Whether the router is ready and router fields are updated client-side

61

*/

62

isReady: boolean;

63

64

/**

65

* Whether the application is in preview mode

66

*/

67

isPreview: boolean;

68

69

/**

70

* Whether the current page is a fallback page

71

*/

72

isFallback: boolean;

73

74

/**

75

* Navigate to a new route

76

* @param url - The URL to navigate to

77

* @param as - Optional URL to show in browser

78

* @param options - Navigation options

79

*/

80

push(url: Url, as?: Url, options?: TransitionOptions): Promise<boolean>;

81

82

/**

83

* Replace the current route without adding to history

84

* @param url - The URL to navigate to

85

* @param as - Optional URL to show in browser

86

* @param options - Navigation options

87

*/

88

replace(url: Url, as?: Url, options?: TransitionOptions): Promise<boolean>;

89

90

/**

91

* Reload the current route

92

*/

93

reload(): void;

94

95

/**

96

* Navigate back in the browser history

97

*/

98

back(): void;

99

100

/**

101

* Navigate forward in the browser history

102

*/

103

forward(): void;

104

105

/**

106

* Prefetch a route for faster navigation

107

* @param url - The URL to prefetch

108

* @param asPath - Optional URL to show in browser

109

* @param options - Prefetch options

110

*/

111

prefetch(url: Url, asPath?: Url, options?: PrefetchOptions): Promise<void>;

112

113

/**

114

* Set a callback to execute before route changes

115

* @param callback - Callback function receiving route state

116

*/

117

beforePopState(callback: BeforePopStateCallback): void;

118

119

/**

120

* Router events for listening to navigation lifecycle

121

*/

122

events: RouterEvents;

123

}

124

125

interface TransitionOptions {

126

shallow?: boolean;

127

locale?: string | false;

128

scroll?: boolean;

129

}

130

131

interface PrefetchOptions {

132

priority?: boolean;

133

locale?: string | false;

134

}

135

136

type Url = string | UrlObject;

137

138

interface UrlObject {

139

auth?: string | null;

140

hash?: string | null;

141

host?: string | null;

142

hostname?: string | null;

143

href?: string | null;

144

pathname?: string | null;

145

protocol?: string | null;

146

search?: string | null;

147

slashes?: boolean | null;

148

port?: string | number | null;

149

query?: ParsedUrlQuery | null;

150

}

151

152

interface ParsedUrlQuery {

153

[key: string]: string | string[] | undefined;

154

}

155

```

156

157

**Usage Examples**:

158

159

```typescript

160

import { useRouter } from 'next/router';

161

162

export default function Page() {

163

const router = useRouter();

164

165

// Access route information

166

console.log('Pathname:', router.pathname); // "/products/[id]"

167

console.log('Query:', router.query); // { id: "123", search: "shoes" }

168

console.log('As Path:', router.asPath); // "/products/123?search=shoes"

169

170

// Navigate programmatically

171

const handleNavigate = () => {

172

router.push('/about');

173

router.push({ pathname: '/products', query: { category: 'shoes' } });

174

router.push('/products/123', '/products/shoes'); // URL masking

175

};

176

177

// Replace without history

178

const handleReplace = () => {

179

router.replace('/login');

180

};

181

182

// Shallow routing (same page, different query)

183

const handleFilter = (filter: string) => {

184

router.push(

185

{ pathname: router.pathname, query: { ...router.query, filter } },

186

undefined,

187

{ shallow: true }

188

);

189

};

190

191

// Check if router is ready

192

if (!router.isReady) {

193

return <div>Loading...</div>;

194

}

195

196

return (

197

<div>

198

<button onClick={handleNavigate}>Navigate</button>

199

<p>Current ID: {router.query.id}</p>

200

</div>

201

);

202

}

203

```

204

205

### Router Events

206

207

Listen to navigation lifecycle events for loading states and analytics.

208

209

```typescript { .api }

210

interface RouterEvents {

211

/**

212

* Subscribe to router events

213

* @param event - Event name

214

* @param handler - Event handler function

215

*/

216

on(event: string, handler: (...args: any[]) => void): void;

217

218

/**

219

* Unsubscribe from router events

220

* @param event - Event name

221

* @param handler - Event handler function

222

*/

223

off(event: string, handler: (...args: any[]) => void): void;

224

}

225

```

226

227

**Available Events**:

228

- `routeChangeStart(url, { shallow })` - Route change started

229

- `routeChangeComplete(url, { shallow })` - Route change completed

230

- `routeChangeError(err, url, { shallow })` - Route change error

231

- `beforeHistoryChange(url, { shallow })` - Before browser history change

232

- `hashChangeStart(url, { shallow })` - Hash change started

233

- `hashChangeComplete(url, { shallow })` - Hash change completed

234

235

**Usage Examples**:

236

237

```typescript

238

import { useRouter } from 'next/router';

239

import { useEffect } from 'react';

240

241

export default function App({ Component, pageProps }) {

242

const router = useRouter();

243

244

useEffect(() => {

245

const handleStart = (url: string) => {

246

console.log(`Loading: ${url}`);

247

};

248

249

const handleComplete = (url: string) => {

250

console.log(`Loaded: ${url}`);

251

};

252

253

const handleError = (err: Error, url: string) => {

254

console.error(`Error loading ${url}:`, err);

255

};

256

257

router.events.on('routeChangeStart', handleStart);

258

router.events.on('routeChangeComplete', handleComplete);

259

router.events.on('routeChangeError', handleError);

260

261

return () => {

262

router.events.off('routeChangeStart', handleStart);

263

router.events.off('routeChangeComplete', handleComplete);

264

router.events.off('routeChangeError', handleError);

265

};

266

}, [router]);

267

268

return <Component {...pageProps} />;

269

}

270

```

271

272

### GetStaticProps

273

274

Static generation with data fetching at build time. Generates static HTML pages that can be cached by a CDN.

275

276

```typescript { .api }

277

import type { GetStaticProps, GetStaticPropsContext, GetStaticPropsResult } from 'next';

278

279

/**

280

* Data fetching function for static generation

281

* @param context - Context object with params, preview data, and locales

282

* @returns Props and revalidation configuration

283

*/

284

type GetStaticProps<Props = any, Params = ParsedUrlQuery, Preview = any> = (

285

context: GetStaticPropsContext<Params, Preview>

286

) => Promise<GetStaticPropsResult<Props>> | GetStaticPropsResult<Props>;

287

288

interface GetStaticPropsContext<Params = ParsedUrlQuery, Preview = any> {

289

/**

290

* Dynamic route parameters

291

*/

292

params?: Params;

293

294

/**

295

* Preview mode data

296

*/

297

preview?: boolean;

298

previewData?: Preview;

299

300

/**

301

* Current locale

302

*/

303

locale?: string;

304

305

/**

306

* All configured locales

307

*/

308

locales?: string[];

309

310

/**

311

* Default locale

312

*/

313

defaultLocale?: string;

314

315

/**

316

* Revalidation request (ISR)

317

*/

318

revalidateReason?: 'on-demand' | 'stale';

319

}

320

321

type GetStaticPropsResult<Props> =

322

| { props: Props; revalidate?: number | boolean; notFound?: never; redirect?: never }

323

| { props?: never; revalidate?: number | boolean; notFound: true; redirect?: never }

324

| { props?: never; revalidate?: number | boolean; notFound?: never; redirect: Redirect };

325

326

interface Redirect {

327

destination: string;

328

permanent: boolean;

329

statusCode?: number;

330

basePath?: boolean;

331

}

332

```

333

334

**Usage Examples**:

335

336

```typescript

337

import type { GetStaticProps } from 'next';

338

339

interface Post {

340

id: string;

341

title: string;

342

content: string;

343

}

344

345

interface PageProps {

346

post: Post;

347

}

348

349

// Basic usage

350

export const getStaticProps: GetStaticProps<PageProps> = async () => {

351

const post = await fetchPost();

352

353

return {

354

props: {

355

post,

356

},

357

};

358

};

359

360

// With revalidation (ISR)

361

export const getStaticProps: GetStaticProps<PageProps> = async () => {

362

const post = await fetchPost();

363

364

return {

365

props: {

366

post,

367

},

368

revalidate: 60, // Revalidate every 60 seconds

369

};

370

};

371

372

// With dynamic params

373

export const getStaticProps: GetStaticProps<PageProps> = async (context) => {

374

const { id } = context.params as { id: string };

375

const post = await fetchPost(id);

376

377

// Return 404 if post not found

378

if (!post) {

379

return {

380

notFound: true,

381

};

382

}

383

384

return {

385

props: {

386

post,

387

},

388

};

389

};

390

391

// With redirect

392

export const getStaticProps: GetStaticProps<PageProps> = async (context) => {

393

const post = await fetchPost();

394

395

if (post.draft && !context.preview) {

396

return {

397

redirect: {

398

destination: '/',

399

permanent: false,

400

},

401

};

402

}

403

404

return {

405

props: {

406

post,

407

},

408

};

409

};

410

411

// With preview mode

412

export const getStaticProps: GetStaticProps<PageProps> = async (context) => {

413

const post = await fetchPost({

414

preview: context.preview,

415

previewData: context.previewData,

416

});

417

418

return {

419

props: {

420

post,

421

},

422

};

423

};

424

425

export default function Post({ post }: PageProps) {

426

return (

427

<article>

428

<h1>{post.title}</h1>

429

<p>{post.content}</p>

430

</article>

431

);

432

}

433

```

434

435

### GetStaticPaths

436

437

Specify dynamic routes to pre-render at build time. Required for dynamic routes using getStaticProps.

438

439

```typescript { .api }

440

import type { GetStaticPaths, GetStaticPathsContext, GetStaticPathsResult } from 'next';

441

442

/**

443

* Define which dynamic routes to pre-render at build time

444

* @param context - Context object with locales

445

* @returns Paths to pre-render and fallback behavior

446

*/

447

type GetStaticPaths<Params = ParsedUrlQuery> = (

448

context: GetStaticPathsContext

449

) => Promise<GetStaticPathsResult<Params>> | GetStaticPathsResult<Params>;

450

451

interface GetStaticPathsContext {

452

/**

453

* All configured locales

454

*/

455

locales?: string[];

456

457

/**

458

* Default locale

459

*/

460

defaultLocale?: string;

461

}

462

463

interface GetStaticPathsResult<Params = ParsedUrlQuery> {

464

/**

465

* Array of paths to pre-render

466

*/

467

paths: Array<string | { params: Params; locale?: string }>;

468

469

/**

470

* Fallback behavior for paths not in paths array

471

* - false: 404 for non-generated paths

472

* - true: Generate on first request, show loading

473

* - 'blocking': Generate on first request, wait for HTML

474

*/

475

fallback: boolean | 'blocking';

476

}

477

```

478

479

**Usage Examples**:

480

481

```typescript

482

import type { GetStaticPaths, GetStaticProps } from 'next';

483

484

// Basic usage

485

export const getStaticPaths: GetStaticPaths = async () => {

486

const posts = await getAllPosts();

487

488

const paths = posts.map((post) => ({

489

params: { id: post.id },

490

}));

491

492

return {

493

paths,

494

fallback: false, // 404 for non-generated paths

495

};

496

};

497

498

// With fallback: true

499

export const getStaticPaths: GetStaticPaths = async () => {

500

// Only pre-render most popular posts

501

const popularPosts = await getPopularPosts();

502

503

const paths = popularPosts.map((post) => ({

504

params: { id: post.id },

505

}));

506

507

return {

508

paths,

509

fallback: true, // Other posts generated on-demand

510

};

511

};

512

513

export const getStaticProps: GetStaticProps = async (context) => {

514

const { id } = context.params as { id: string };

515

const post = await fetchPost(id);

516

517

if (!post) {

518

return {

519

notFound: true,

520

};

521

}

522

523

return {

524

props: {

525

post,

526

},

527

revalidate: 60,

528

};

529

};

530

531

export default function Post({ post }) {

532

const router = useRouter();

533

534

// Show loading state when fallback: true

535

if (router.isFallback) {

536

return <div>Loading...</div>;

537

}

538

539

return (

540

<article>

541

<h1>{post.title}</h1>

542

<p>{post.content}</p>

543

</article>

544

);

545

}

546

547

// With catch-all routes

548

// pages/docs/[...slug].tsx

549

export const getStaticPaths: GetStaticPaths = async () => {

550

const docs = await getAllDocs();

551

552

const paths = docs.map((doc) => ({

553

params: { slug: doc.path.split('/') },

554

}));

555

556

return {

557

paths,

558

fallback: 'blocking',

559

};

560

};

561

562

// With locales

563

export const getStaticPaths: GetStaticPaths = async ({ locales }) => {

564

const posts = await getAllPosts();

565

566

const paths = posts.flatMap((post) =>

567

locales?.map((locale) => ({

568

params: { id: post.id },

569

locale,

570

})) || [{ params: { id: post.id } }]

571

);

572

573

return {

574

paths,

575

fallback: false,

576

};

577

};

578

```

579

580

### GetServerSideProps

581

582

Server-side rendering with data fetching on each request. Useful for frequently changing data or authenticated content.

583

584

```typescript { .api }

585

import type { GetServerSideProps, GetServerSidePropsContext, GetServerSidePropsResult } from 'next';

586

587

/**

588

* Data fetching function for server-side rendering

589

* @param context - Context object with request, response, params, and query

590

* @returns Props or redirect/notFound response

591

*/

592

type GetServerSideProps<Props = any, Params = ParsedUrlQuery, Preview = any> = (

593

context: GetServerSidePropsContext<Params, Preview>

594

) => Promise<GetServerSidePropsResult<Props>>;

595

596

interface GetServerSidePropsContext<Params = ParsedUrlQuery, Preview = any> {

597

/**

598

* HTTP request object

599

*/

600

req: IncomingMessage & {

601

cookies: Partial<{ [key: string]: string }>;

602

};

603

604

/**

605

* HTTP response object

606

*/

607

res: ServerResponse;

608

609

/**

610

* Dynamic route parameters

611

*/

612

params?: Params;

613

614

/**

615

* Query string parameters

616

*/

617

query: ParsedUrlQuery;

618

619

/**

620

* Preview mode data

621

*/

622

preview?: boolean;

623

previewData?: Preview;

624

625

/**

626

* The resolved URL path

627

*/

628

resolvedUrl: string;

629

630

/**

631

* Current locale

632

*/

633

locale?: string;

634

635

/**

636

* All configured locales

637

*/

638

locales?: string[];

639

640

/**

641

* Default locale

642

*/

643

defaultLocale?: string;

644

}

645

646

type GetServerSidePropsResult<Props> =

647

| { props: Props | Promise<Props>; notFound?: never; redirect?: never }

648

| { props?: never; notFound: true; redirect?: never }

649

| { props?: never; notFound?: never; redirect: Redirect };

650

651

interface Redirect {

652

destination: string;

653

permanent: boolean;

654

statusCode?: number;

655

basePath?: boolean;

656

}

657

```

658

659

**Usage Examples**:

660

661

```typescript

662

import type { GetServerSideProps } from 'next';

663

664

interface User {

665

id: string;

666

name: string;

667

email: string;

668

}

669

670

interface PageProps {

671

user: User;

672

}

673

674

// Basic usage

675

export const getServerSideProps: GetServerSideProps<PageProps> = async (context) => {

676

const user = await fetchUser();

677

678

return {

679

props: {

680

user,

681

},

682

};

683

};

684

685

// With authentication

686

export const getServerSideProps: GetServerSideProps<PageProps> = async (context) => {

687

const session = await getSession(context.req, context.res);

688

689

if (!session) {

690

return {

691

redirect: {

692

destination: '/login',

693

permanent: false,

694

},

695

};

696

}

697

698

const user = await fetchUser(session.userId);

699

700

return {

701

props: {

702

user,

703

},

704

};

705

};

706

707

// With dynamic params and query

708

export const getServerSideProps: GetServerSideProps<PageProps> = async (context) => {

709

const { id } = context.params as { id: string };

710

const { tab } = context.query;

711

712

const user = await fetchUser(id);

713

714

if (!user) {

715

return {

716

notFound: true,

717

};

718

}

719

720

return {

721

props: {

722

user,

723

activeTab: tab || 'profile',

724

},

725

};

726

};

727

728

// With cookies

729

export const getServerSideProps: GetServerSideProps<PageProps> = async (context) => {

730

const token = context.req.cookies.token;

731

732

if (!token) {

733

return {

734

redirect: {

735

destination: '/login',

736

permanent: false,

737

},

738

};

739

}

740

741

const user = await fetchUser(token);

742

743

return {

744

props: {

745

user,

746

},

747

};

748

};

749

750

// Set response headers

751

export const getServerSideProps: GetServerSideProps<PageProps> = async (context) => {

752

const user = await fetchUser();

753

754

// Set cache headers

755

context.res.setHeader(

756

'Cache-Control',

757

'public, s-maxage=10, stale-while-revalidate=59'

758

);

759

760

return {

761

props: {

762

user,

763

},

764

};

765

};

766

767

export default function Profile({ user }: PageProps) {

768

return (

769

<div>

770

<h1>{user.name}</h1>

771

<p>{user.email}</p>

772

</div>

773

);

774

}

775

```

776

777

### API Routes

778

779

Create API endpoints within your Next.js application using file-based routing in the pages/api directory.

780

781

```typescript { .api }

782

import type { NextApiRequest, NextApiResponse, NextApiHandler } from 'next';

783

784

/**

785

* HTTP request object for API routes

786

*/

787

interface NextApiRequest extends IncomingMessage {

788

/**

789

* Query string parameters

790

*/

791

query: ParsedUrlQuery;

792

793

/**

794

* Request cookies

795

*/

796

cookies: Partial<{ [key: string]: string }>;

797

798

/**

799

* Parsed request body

800

*/

801

body: any;

802

803

/**

804

* Environment variables

805

*/

806

env: Record<string, string>;

807

808

/**

809

* Preview mode status

810

*/

811

preview?: boolean;

812

813

/**

814

* Preview mode data

815

*/

816

previewData?: any;

817

}

818

819

/**

820

* HTTP response object for API routes

821

*/

822

interface NextApiResponse<Data = any> extends ServerResponse {

823

/**

824

* Set the response status code

825

* @param statusCode - HTTP status code

826

*/

827

status(statusCode: number): NextApiResponse<Data>;

828

829

/**

830

* Send a JSON response

831

* @param body - Response data

832

*/

833

json(body: Data): void;

834

835

/**

836

* Send any response

837

* @param body - Response body

838

*/

839

send(body: Data): void;

840

841

/**

842

* Redirect to another URL

843

* @param statusOrUrl - Status code or URL

844

* @param url - URL if first param is status

845

*/

846

redirect(url: string): void;

847

redirect(status: number, url: string): void;

848

849

/**

850

* Set the response headers

851

* @param name - Header name

852

* @param value - Header value

853

*/

854

setHeader(name: string, value: string | number | string[]): this;

855

856

/**

857

* Revalidate a path (ISR)

858

* @param urlPath - Path to revalidate

859

*/

860

revalidate(urlPath: string): Promise<void>;

861

862

/**

863

* Set preview mode data

864

* @param data - Preview data

865

*/

866

setPreviewData(data: any, options?: {

867

maxAge?: number;

868

path?: string;

869

}): NextApiResponse<Data>;

870

871

/**

872

* Clear preview mode

873

*/

874

clearPreviewData(): NextApiResponse<Data>;

875

}

876

877

/**

878

* API route handler function type

879

* @param req - Request object

880

* @param res - Response object

881

*/

882

type NextApiHandler<Data = any> = (

883

req: NextApiRequest,

884

res: NextApiResponse<Data>

885

) => void | Promise<void>;

886

```

887

888

**Usage Examples**:

889

890

```typescript

891

import type { NextApiRequest, NextApiResponse } from 'next';

892

893

// Basic API route

894

// pages/api/hello.ts

895

export default function handler(

896

req: NextApiRequest,

897

res: NextApiResponse

898

) {

899

res.status(200).json({ message: 'Hello World' });

900

}

901

902

// With type-safe response

903

interface User {

904

id: string;

905

name: string;

906

}

907

908

type ResponseData = User | { error: string };

909

910

export default async function handler(

911

req: NextApiRequest,

912

res: NextApiResponse<ResponseData>

913

) {

914

const user = await fetchUser();

915

916

if (!user) {

917

return res.status(404).json({ error: 'User not found' });

918

}

919

920

res.status(200).json(user);

921

}

922

923

// Handle different HTTP methods

924

export default async function handler(

925

req: NextApiRequest,

926

res: NextApiResponse

927

) {

928

if (req.method === 'GET') {

929

const users = await getUsers();

930

return res.status(200).json(users);

931

}

932

933

if (req.method === 'POST') {

934

const newUser = await createUser(req.body);

935

return res.status(201).json(newUser);

936

}

937

938

if (req.method === 'PUT') {

939

const updatedUser = await updateUser(req.body);

940

return res.status(200).json(updatedUser);

941

}

942

943

if (req.method === 'DELETE') {

944

await deleteUser(req.query.id as string);

945

return res.status(204).end();

946

}

947

948

// Method not allowed

949

res.setHeader('Allow', ['GET', 'POST', 'PUT', 'DELETE']);

950

res.status(405).end(`Method ${req.method} Not Allowed`);

951

}

952

953

// Dynamic API route with params

954

// pages/api/posts/[id].ts

955

export default async function handler(

956

req: NextApiRequest,

957

res: NextApiResponse

958

) {

959

const { id } = req.query;

960

961

const post = await getPost(id as string);

962

963

if (!post) {

964

return res.status(404).json({ error: 'Post not found' });

965

}

966

967

res.status(200).json(post);

968

}

969

970

// With authentication

971

export default async function handler(

972

req: NextApiRequest,

973

res: NextApiResponse

974

) {

975

const token = req.cookies.token;

976

977

if (!token) {

978

return res.status(401).json({ error: 'Unauthorized' });

979

}

980

981

const user = await verifyToken(token);

982

983

if (!user) {

984

return res.status(401).json({ error: 'Invalid token' });

985

}

986

987

const data = await getProtectedData(user.id);

988

res.status(200).json(data);

989

}

990

991

// Revalidate on-demand (ISR)

992

export default async function handler(

993

req: NextApiRequest,

994

res: NextApiResponse

995

) {

996

if (req.query.secret !== process.env.REVALIDATE_SECRET) {

997

return res.status(401).json({ message: 'Invalid token' });

998

}

999

1000

try {

1001

await res.revalidate('/posts/1');

1002

return res.json({ revalidated: true });

1003

} catch (err) {

1004

return res.status(500).send('Error revalidating');

1005

}

1006

}

1007

1008

// Preview mode

1009

// pages/api/preview.ts

1010

export default async function handler(

1011

req: NextApiRequest,

1012

res: NextApiResponse

1013

) {

1014

const { secret, slug } = req.query;

1015

1016

if (secret !== process.env.PREVIEW_SECRET) {

1017

return res.status(401).json({ message: 'Invalid token' });

1018

}

1019

1020

const post = await getPreviewPost(slug as string);

1021

1022

if (!post) {

1023

return res.status(401).json({ message: 'Invalid slug' });

1024

}

1025

1026

res.setPreviewData({ postId: post.id });

1027

res.redirect(post.slug);

1028

}

1029

1030

// pages/api/exit-preview.ts

1031

export default async function handler(

1032

req: NextApiRequest,

1033

res: NextApiResponse

1034

) {

1035

res.clearPreviewData();

1036

res.redirect('/');

1037

}

1038

```

1039

1040

### PageConfig

1041

1042

Page-level configuration for API routes and pages to control runtime behavior.

1043

1044

```typescript { .api }

1045

/**

1046

* Configuration options for pages and API routes

1047

*/

1048

interface PageConfig {

1049

/**

1050

* API route specific configuration

1051

*/

1052

api?: {

1053

/**

1054

* Maximum request body size (default: 1mb)

1055

*/

1056

bodyParser?: {

1057

sizeLimit?: string | number;

1058

} | false;

1059

1060

/**

1061

* Maximum response body size in bytes (default: 4mb)

1062

*/

1063

responseLimit?: string | number | false;

1064

1065

/**

1066

* External resolver flag (for custom servers)

1067

*/

1068

externalResolver?: boolean;

1069

};

1070

1071

/**

1072

* Runtime environment: 'nodejs' or 'edge'

1073

*/

1074

runtime?: 'nodejs' | 'edge';

1075

1076

/**

1077

* Disable runtime JS in production

1078

*/

1079

unstable_runtimeJS?: boolean;

1080

1081

/**

1082

* Disable JS preload

1083

*/

1084

unstable_JsPreload?: boolean;

1085

1086

/**

1087

* Maximum execution duration in seconds

1088

*/

1089

maxDuration?: number;

1090

}

1091

```

1092

1093

**Usage Examples**:

1094

1095

```typescript

1096

import type { NextApiRequest, NextApiResponse } from 'next';

1097

1098

// Disable body parsing for file uploads

1099

export const config: PageConfig = {

1100

api: {

1101

bodyParser: false,

1102

},

1103

};

1104

1105

export default async function handler(

1106

req: NextApiRequest,

1107

res: NextApiResponse

1108

) {

1109

// Handle multipart form data manually

1110

const formData = await parseMultipartForm(req);

1111

res.status(200).json({ success: true });

1112

}

1113

1114

// Increase body size limit

1115

export const config: PageConfig = {

1116

api: {

1117

bodyParser: {

1118

sizeLimit: '10mb',

1119

},

1120

},

1121

};

1122

1123

// Edge runtime

1124

export const config: PageConfig = {

1125

runtime: 'edge',

1126

};

1127

1128

export default async function handler(

1129

req: NextApiRequest,

1130

res: NextApiResponse

1131

) {

1132

// Runs on Edge Runtime

1133

return res.json({ message: 'Edge function' });

1134

}

1135

1136

// Increase execution timeout (on supported plans)

1137

export const config: PageConfig = {

1138

maxDuration: 60, // 60 seconds

1139

};

1140

```

1141

1142

### withRouter HOC

1143

1144

Higher-order component to inject the router object into any component.

1145

1146

```typescript { .api }

1147

import { withRouter } from 'next/router';

1148

import type { WithRouterProps } from 'next/router';

1149

1150

/**

1151

* HOC to inject router into component props

1152

* @param Component - Component to wrap with router

1153

* @returns Component with router prop

1154

*/

1155

function withRouter<P extends WithRouterProps>(

1156

Component: React.ComponentType<P>

1157

): React.ComponentType<Omit<P, keyof WithRouterProps>>;

1158

1159

interface WithRouterProps {

1160

router: NextRouter;

1161

}

1162

```

1163

1164

**Usage Examples**:

1165

1166

```typescript

1167

import { withRouter } from 'next/router';

1168

import type { NextRouter } from 'next/router';

1169

1170

// Class component

1171

class MyComponent extends React.Component<{ router: NextRouter }> {

1172

componentDidMount() {

1173

console.log('Current path:', this.props.router.pathname);

1174

}

1175

1176

render() {

1177

return <div>Path: {this.props.router.pathname}</div>;

1178

}

1179

}

1180

1181

export default withRouter(MyComponent);

1182

1183

// Functional component (use useRouter hook instead when possible)

1184

function MyFunctionalComponent({ router }: { router: NextRouter }) {

1185

return (

1186

<div>

1187

<p>Current path: {router.pathname}</p>

1188

<button onClick={() => router.push('/about')}>

1189

Go to About

1190

</button>

1191

</div>

1192

);

1193

}

1194

1195

export default withRouter(MyFunctionalComponent);

1196

```

1197

1198

### Type Utilities

1199

1200

Helper types to infer props from data fetching functions.

1201

1202

```typescript { .api }

1203

import type { InferGetStaticPropsType, InferGetServerSidePropsType } from 'next';

1204

1205

/**

1206

* Infer the props type from a GetStaticProps function

1207

*/

1208

type InferGetStaticPropsType<T extends (...args: any) => any> =

1209

T extends GetStaticProps<infer P> ? P : never;

1210

1211

/**

1212

* Infer the props type from a GetServerSideProps function

1213

*/

1214

type InferGetServerSidePropsType<T extends (...args: any) => any> =

1215

T extends GetServerSideProps<infer P> ? P : never;

1216

```

1217

1218

**Usage Examples**:

1219

1220

```typescript

1221

// Infer props from getStaticProps

1222

export const getStaticProps = async () => {

1223

const posts = await getPosts();

1224

return {

1225

props: {

1226

posts,

1227

timestamp: Date.now(),

1228

},

1229

};

1230

};

1231

1232

type PageProps = InferGetStaticPropsType<typeof getStaticProps>;

1233

// PageProps = { posts: Post[]; timestamp: number }

1234

1235

export default function Page({ posts, timestamp }: PageProps) {

1236

return <div>{posts.length} posts</div>;

1237

}

1238

1239

// Infer props from getServerSideProps

1240

export const getServerSideProps = async (context) => {

1241

const user = await getUser(context.params.id);

1242

return {

1243

props: {

1244

user,

1245

isAdmin: user.role === 'admin',

1246

},

1247

};

1248

};

1249

1250

type ProfileProps = InferGetServerSidePropsType<typeof getServerSideProps>;

1251

// ProfileProps = { user: User; isAdmin: boolean }

1252

1253

export default function Profile({ user, isAdmin }: ProfileProps) {

1254

return <div>{user.name}</div>;

1255

}

1256

```

1257

1258

## Types

1259

1260

```typescript { .api }

1261

interface NextRouter {

1262

pathname: string;

1263

query: ParsedUrlQuery;

1264

asPath: string;

1265

basePath: string;

1266

locale?: string;

1267

locales?: string[];

1268

defaultLocale?: string;

1269

isReady: boolean;

1270

isPreview: boolean;

1271

isFallback: boolean;

1272

push(url: Url, as?: Url, options?: TransitionOptions): Promise<boolean>;

1273

replace(url: Url, as?: Url, options?: TransitionOptions): Promise<boolean>;

1274

reload(): void;

1275

back(): void;

1276

forward(): void;

1277

prefetch(url: Url, asPath?: Url, options?: PrefetchOptions): Promise<void>;

1278

beforePopState(callback: BeforePopStateCallback): void;

1279

events: RouterEvents;

1280

}

1281

1282

interface ParsedUrlQuery {

1283

[key: string]: string | string[] | undefined;

1284

}

1285

1286

interface TransitionOptions {

1287

shallow?: boolean;

1288

locale?: string | false;

1289

scroll?: boolean;

1290

}

1291

1292

interface PrefetchOptions {

1293

priority?: boolean;

1294

locale?: string | false;

1295

}

1296

1297

type Url = string | UrlObject;

1298

1299

interface UrlObject {

1300

auth?: string | null;

1301

hash?: string | null;

1302

host?: string | null;

1303

hostname?: string | null;

1304

href?: string | null;

1305

pathname?: string | null;

1306

protocol?: string | null;

1307

search?: string | null;

1308

slashes?: boolean | null;

1309

port?: string | number | null;

1310

query?: ParsedUrlQuery | null;

1311

}

1312

1313

interface Redirect {

1314

destination: string;

1315

permanent: boolean;

1316

statusCode?: number;

1317

basePath?: boolean;

1318

}

1319

1320

type InferGetStaticPropsType<T extends (...args: any) => any> =

1321

T extends GetStaticProps<infer P> ? P : never;

1322

1323

type InferGetServerSidePropsType<T extends (...args: any) => any> =

1324

T extends GetServerSideProps<infer P> ? P : never;

1325

```

1326

1327

## Important Notes

1328

1329

- Pages Router is the legacy routing system; App Router is recommended for new projects

1330

- All Pages Router components are client components by default

1331

- getStaticProps and getStaticPaths only run at build time (or during revalidation)

1332

- getServerSideProps runs on every request

1333

- API routes should not be called from getStaticProps or getServerSideProps (call data layer directly)

1334

- Use ISR (Incremental Static Regeneration) with revalidate for dynamic content that doesn't change frequently

1335

- API routes are not bundled in the client-side code

1336

- API routes can use Node.js modules and don't increase client bundle size

1337