---
title: "TypeScript Plugin"
description: "The Next.js TypeScript plugin acts as an integrated language service extension that enhances the developer experience within the app directory by enforcing correct file conventions, validating segm..."
last_updated: "2026-10-12T06:38:56.845597+00:00"
canonical_url: "https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/built-in-features/typescript-plugin"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/next/src/server/typescript/rules/config.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/config.ts)
- [packages/next/src/server/typescript/index.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/index.ts)
- [packages/next/src/server/typescript/rules/client-boundary.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/client-boundary.ts)
- [packages/next/src/build/webpack/plugins/next-types-plugin/index.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts)
- [packages/next/src/build/segment-config/app/app-segment-config.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segment-config.ts)
- [packages/next/src/server/typescript/rules/entry.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/entry.ts)
- [packages/next/src/server/app-render/instant-validation/instant-config.tsx](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/instant-validation/instant-config.tsx)
- [packages/next/src/server/app-render/instant-validation/instant-validation.tsx](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/instant-validation/instant-validation.tsx)
- [packages/next/src/server/typescript/rules/error.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/error.ts)
- [packages/next/src/server/typescript/utils.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts)
- [packages/next/src/lib/typescript/diagnosticFormatter.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/lib/typescript/diagnosticFormatter.ts)
- [packages/next/src/server/typescript/rules/metadata.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/metadata.ts)
- [packages/next/src/server/lib/router-utils/typegen.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/lib/router-utils/typegen.ts)
- [packages/next/src/build/webpack/loaders/next-app-loader/index.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/loaders/next-app-loader/index.ts)
- [packages/next/src/server/typescript/rules/server-boundary.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/server-boundary.ts)
- [packages/next/src/build/babel/plugins/next-page-config.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/babel/plugins/next-page-config.ts)
- [packages/next/src/server/typescript/rules/server.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/server.ts)
- [packages/next/src/server/typescript/constant.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/constant.ts)
- [packages/next/src/build/segment-config/app/app-segments.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/app/app-segments.ts)
- [packages/next/src/next-devtools/userspace/app/segment-explorer-node.tsx](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/next-devtools/userspace/app/segment-explorer-node.tsx)
- [packages/next/src/server/app-render/segment-explorer-path.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/segment-explorer-path.ts)
- [packages/next/src/lib/verify-typescript-setup.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/lib/verify-typescript-setup.ts)
- [packages/next/src/lib/typescript/writeConfigurationDefaults.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/lib/typescript/writeConfigurationDefaults.ts)
- [packages/next/src/server/config-schema.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/config-schema.ts)
- [packages/next/src/build/segment-config/pages/pages-segment-config.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/segment-config/pages/pages-segment-config.ts)
- [packages/next/src/server/app-render/segment-config/ensure-static.ts](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/app-render/segment-config/ensure-static.ts)
</details>

## Overview

The Next.js TypeScript plugin acts as an integrated language service extension that enhances the developer experience within the `app` directory by enforcing correct file conventions, validating segment configuration exports, and policing component boundaries. It provides intelligent autocompletion, hover hints, and diagnostic error checking directly inside editors supporting the TypeScript Language Service protocol.
Sources: [packages/next/src/server/typescript/index.ts:1-10](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/index.ts#L1-L10)

By proxying language service requests, the plugin intercepts semantic diagnostics, completion entries, and quick info lookups to restrict unauthorized React APIs in server components, validate route segment options, verify serialization constraints for `"use client"` and `"use server"` boundaries, and enforce proper component signatures.
Sources: [packages/next/src/server/typescript/index.ts:60-175](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/index.ts#L60-L175), [packages/next/src/server/typescript/index.ts:178-270](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/index.ts#L178-L270)

## Language service plugin architecture

### Plugin Initialization and Request Proxying

The Next.js TypeScript plugin exports a `createTSPlugin` function adhering to the `tsModule.server.PluginModuleFactory` signature. It receives a factory context containing the TypeScript module reference and returns an inner `create` closure taking a `tsModule.server.PluginCreateInfo` object. The plugin checks user configurations in `tsconfig.json` through `info.config.enabled`, defaulting to `true`. If disabled, it immediately returns the unmodified language service. When enabled, it calls `init` with the TypeScript module and creation info to set up project directory boundaries and regular expression matching for the `app` directory.
Sources: [packages/next/src/server/typescript/index.ts:31-48](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/index.ts#L31-L48), [packages/next/src/server/typescript/utils.ts:15-27](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L15-L27)

To intercept language service queries without breaking standard editing features, the plugin establishes a decorated proxy object using `Object.create(null)` and iterates over all keys of `info.languageService`. Each method is wrapped to delegate execution back to the underlying language service instance. Specific handlers such as `getCompletionsAtPosition`, `getCompletionEntryDetails`, `getQuickInfoAtPosition`, and `getSemanticDiagnostics` are overridden to inject custom diagnostics, filter out disallowed completions, or modify quick info tooltips for Next.js app directory files.
Sources: [packages/next/src/server/typescript/index.ts:51-176](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/index.ts#L51-L176), [packages/next/src/server/typescript/index.ts:178-270](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/index.ts#L178-L270)

> [!NOTE]
> The language service proxy copies all native methods from `info.languageService` into a new dictionary object to preserve editor functionality while selectively layering custom AST rule checks over app directory files.
> Sources: [packages/next/src/server/typescript/index.ts:51-57](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/index.ts#L51-L57)

### Call-Chain Execution Walkthrough: `create` to `log`

During semantic diagnostics collection or entry analysis, the plugin executes the explicit call chain `create()` → `getEntryInfo()` → `getSource()` → `log()`. When diagnostic checking evaluates a file via `getSemanticDiagnostics`, it invokes `getEntryInfo(fileName, true)` from `packages/next/src/server/typescript/index.ts:187`. `getEntryInfo()` immediately calls `getSource(fileName)` from `packages/next/src/server/typescript/utils.ts:122` to query the language service program for the file's AST `SourceFile`. When initialization runs, `init()` invokes `log(message)` from `packages/next/src/server/typescript/utils.ts:26` to record plugin status through the project service logger.
Sources: [packages/next/src/server/typescript/index.ts:187-190](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/index.ts#L187-L190), [packages/next/src/server/typescript/utils.ts:10-12](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L10-L12), [packages/next/src/server/typescript/utils.ts:26-26](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L26-L26), [packages/next/src/server/typescript/utils.ts:51-58](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L51-L58), [packages/next/src/server/typescript/utils.ts:118-123](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L118-L123)

```mermaid
sequenceDiagram
    participant Index as index.ts (create)
    participant Utils as utils.ts (getEntryInfo)
    participant Program as utils.ts (getSource)
    participant Logger as utils.ts (log)

    Index->>Utils: getEntryInfo(fileName, true)
    Utils->>Program: getSource(fileName)
    Program->>Utils: returns tsModule.SourceFile
    Utils->>Logger: log(message) writes via project service
```
Sources: [packages/next/src/server/typescript/index.ts:187-190](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/index.ts#L187-L190), [packages/next/src/server/typescript/utils.ts:10-12](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L10-L12), [packages/next/src/server/typescript/utils.ts:26-26](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L26-L26), [packages/next/src/server/typescript/utils.ts:51-58](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L51-L58), [packages/next/src/server/typescript/utils.ts:118-123](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L118-L123)

### AST Utilities and Request Dispatching

The plugin provides helper functions in `utils.ts` to inspect Abstract Syntax Tree nodes and evaluate file paths against the `app` directory structure. Path validation relies on `appDirRegExp`, generated dynamically from the project's current working directory to match both standard `app` folders and `src/app` layouts.
Sources: [packages/next/src/server/typescript/utils.ts:19-27](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L19-L27), [packages/next/src/server/typescript/utils.ts:101-115](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L101-L115)

| Utility Function | Parameter Signature | Return Type | Purpose |
| :--- | :--- | :--- | :--- |
| `init` | `opts: { ts: TypeScript, info: PluginCreateInfo }` | `void` | Sets up project directory regex patterns and global references. |
| `getTypeChecker` | none | `tsModule.TypeChecker \| undefined` | Retrieves the type checker from the active language service program. |
| `getSource` | `fileName: string` | `tsModule.SourceFile \| undefined` | Fetches the parsed AST `SourceFile` for a given file path. |
| `isPositionInsideNode` | `position: number, node: tsModule.Node` | `boolean` | Verifies whether an editor cursor position falls within a node span. |
| `isDefaultFunctionExport` | `node: tsModule.Node` | boolean guard | Checks if an AST node represents an `export default function` declaration. |
| `isInsideApp` | `filePath: string` | `boolean` | Tests whether a file path resides inside the configured `app` directory. |
| `isAppEntryFile` | `filePath: string` | `boolean` | Confirms if a file path matches `page` or `layout` extensions within `app`. |
| `getEntryInfo` | `fileName: string, throwOnInvalidDirective?: boolean` | `{ client: boolean, server: boolean }` | Parses leading string literals to detect `"use client"` or `"use server"` directives. |

Sources: [packages/next/src/server/typescript/utils.ts:15-181](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L15-L181)

> [!WARNING]
> Directive scanning in `getEntryInfo` stops tracking boundaries as soon as a non-expression statement or non-string literal node is encountered; directives placed below other statements are treated as invalid and will throw diagnostic errors if strict validation is enabled.
> Sources: [packages/next/src/server/typescript/utils.ts:128-176](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/utils.ts#L128-L176)

## Segment config validation and completion

### Segment Configuration Validation and Autocompletion

The TypeScript plugin validates route segment configurations and allowed entry exports within Next.js application files. It verifies variable declarations against a defined schema of allowed entry identifiers and reports semantic errors when invalid configuration options or values are supplied.
Sources: [packages/next/src/server/typescript/rules/config.ts:1-28](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/config.ts#L1-L28), [packages/next/src/server/typescript/rules/config.ts:620-642](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/config.ts#L620-L642)

| Export Identifier | Description / Allowed Values |
| :--- | :--- |
| `config` | Legacy configuration export object. |
| `generateStaticParams` | Function to generate static route parameters. |
| `unstable_paramMatching` | Experimental parameter matching definition. |
| `unstable_generateParamMatching` | Experimental parameter matching generator function. |
| `metadata` | Static metadata object for the page or layout. |
| `generateMetadata` | Asynchronous or synchronous function returning dynamic `Metadata`. |
| `viewport` | Static viewport configuration object. |
| `generateViewport` | Function returning dynamic viewport settings. |

Sources: [packages/next/src/server/typescript/constant.ts:15-24](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/constant.ts#L15-L24)

> [!WARNING]
> Export names that match neither `ALLOWED_EXPORTS` nor the configuration schema defined in `API_DOCS` trigger `NEXT_TS_ERRORS.INVALID_ENTRY_EXPORT` with code `71002`, flagging the exact token span as an invalid Next.js entry export value.
> Sources: [packages/next/src/server/typescript/constant.ts:3-3](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/constant.ts#L3-L3), [packages/next/src/server/typescript/rules/config.ts:632-641](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/config.ts#L632-L641)

### Metadata Import Code Actions

When autocompleting or inspecting `metadata` or `generateMetadata` entry points, the plugin checks the target source file for an existing type import from the `'next'` module. If no import for `Metadata` is present, it provides an automatic code action to inject `import type { Metadata } from 'next';` directly beneath top-level directive strings such as `"use client"`.
Sources: [packages/next/src/server/typescript/rules/config.ts:504-602](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/config.ts#L504-L602)

> [!NOTE]
> The metadata import insertion visitor inspects top-level string literal statements for expressions starting with `use ` to position the import below directives while avoiding invalid placement.
> Sources: [packages/next/src/server/typescript/rules/config.ts:530-542](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/config.ts#L530-L542)

## Client boundary restrictions and diagnostics

### Validating Client Component Props and Serializability

The TypeScript plugin inspects variable statements and function declarations in files carrying the `"use client"` directive to verify that component props adhere to serialization constraints. When analyzing function parameters, the plugin evaluates type literal members to detect non-serializable property types such as functions, constructors, and class declarations, emitting diagnostic warnings when invalid prop types are supplied across client boundaries.
Sources: [packages/next/src/server/typescript/rules/client-boundary.ts:7-49](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/client-boundary.ts#L7-L49)

```typescript
export const NEXT_TS_ERRORS = {
  INVALID_SERVER_API: 71001,
  INVALID_ENTRY_EXPORT: 71002,
  INVALID_OPTION_VALUE: 71003,
  MISPLACED_ENTRY_DIRECTIVE: 71004,
  INVALID_PAGE_PROP: 71005,
  INVALID_CONFIG_OPTION: 71006,
  INVALID_CLIENT_ENTRY_PROP: 71007,
  INVALID_METADATA_EXPORT: 71008,
  INVALID_ERROR_COMPONENT: 71009,
  INVALID_ENTRY_DIRECTIVE: 71010,
  INVALID_SERVER_ENTRY_RETURN: 71011,
}
```
Sources: [packages/next/src/server/typescript/constant.ts:1-13](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/constant.ts#L1-L13)

> [!WARNING]
> The plugin flags invalid client entry props using diagnostic code `71007` (`NEXT_TS_ERRORS.INVALID_CLIENT_ENTRY_PROP`) with category `DiagnosticCategory.Warning` when encountering function types, constructor types, or class declarations that are not recognized as [Server Actions](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/app-rendering/server-actions) or framework-managed error boundary props.
> Sources: [packages/next/src/server/typescript/rules/client-boundary.ts:88-114](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/client-boundary.ts#L88-L114)

### Server Actions and Error Boundary Exceptions

To accommodate legitimate callback patterns and framework integrations, the plugin applies specific naming and file-path heuristics before raising serializability diagnostics on function-typed props. Properties named `action` or ending with `Action` (such as `formAction`) are permitted under the assumption that they represent Server Actions. Additionally, files matching `error.tsx` or `global-error.tsx` are evaluated against framework-injected recovery functions (`reset` and `retry`), exempting them from client component serialization rules.
Sources: [packages/next/src/server/typescript/rules/client-boundary.ts:43-87](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/client-boundary.ts#L43-L87)

> [!NOTE]
> Structural type checking cannot distinguish between arbitrary closures and Server Actions until TypeScript exposes directive metadata directly in function types, so the plugin uses property naming conventions as a heuristic to avoid high rates of false positives.
> Sources: [packages/next/src/server/typescript/rules/client-boundary.ts:68-74](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/client-boundary.ts#L68-L74)

## Server actions and boundaries validation

### Verifying Async Signatures in Server Modules

The TypeScript plugin validates files governed by the `"use server"` directive to ensure that all exported entities conform to asynchronous execution requirements. Using the type checker, the plugin inspects export declarations, variable statements, arrow functions, function declarations, function expressions, call expressions, and identifiers to verify that every exported member returns a `Promise`.
Sources: [packages/next/src/server/typescript/rules/server-boundary.ts:1-157](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/server-boundary.ts#L1-L157)

```typescript
function isPromiseType(type: tsModule.Type, typeChecker: tsModule.TypeChecker) {
  const typeReferenceType = type as tsModule.TypeReference
  if (!typeReferenceType.target) return false

  // target should be Promise or Promise<...>
  if (
    !/^Promise(<.+>)?$/.test(typeChecker.typeToString(typeReferenceType.target))
  ) {
    return false
  }

  return true
}
```
Sources: [packages/next/src/server/typescript/rules/server-boundary.ts:8-20](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/server-boundary.ts#L8-L20)

> [!WARNING]
> When an export declaration or variable initializer in a server action module fails to return a `Promise`, the plugin reports diagnostic code `71011` (`NEXT_TS_ERRORS.INVALID_SERVER_ENTRY_RETURN`) with the message `The "use server" file can only export async functions.`
> Sources: [packages/next/src/server/typescript/rules/server-boundary.ts:72-81](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/server-boundary.ts#L72-L81), [packages/next/src/server/typescript/constant.ts:1-13](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/constant.ts#L1-L13)

### Server Layer Component Restrictions

Within server components, the language service plugin filters completion entries and inspects import declarations to prevent the usage of disallowed client-side React hooks and class APIs. When processing import declarations from `"react"` or `"react-dom"`, the plugin checks named bindings against explicit blacklists of client APIs such as state and effect hooks.
Sources: [packages/next/src/server/typescript/rules/server.ts:1-90](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/server.ts#L1-L90)

| Module | Disallowed APIs | Diagnostic Code |
| :--- | :--- | :--- |
| `react` | `useState`, `useEffect`, `useEffectEvent`, `useLayoutEffect`, `useDeferredValue`, `useImperativeHandle`, `useInsertionEffect`, `useReducer`, `useRef`, `useSyncExternalStore`, `useTransition`, `Component`, `PureComponent`, `createContext`, `createFactory`, `experimental_useOptimistic`, `useOptimistic`, `useActionState` | `71001` (`NEXT_TS_ERRORS.INVALID_SERVER_API`) |
| `react-dom` | `useFormStatus`, `useFormState` | `71001` (`NEXT_TS_ERRORS.INVALID_SERVER_API`) |

Sources: [packages/next/src/server/typescript/constant.ts:28-52](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/constant.ts#L28-L52), [packages/next/src/server/typescript/rules/server.ts:48-86](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/server.ts#L48-L86)

> [!NOTE]
> The plugin checks both completion entry lists and import declarations to ensure developers receive immediate feedback when attempting to import stateful React primitives inside server layers.
> Sources: [packages/next/src/server/typescript/rules/server.ts:11-33](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/server.ts#L11-L33), [packages/next/src/server/typescript/rules/server.ts:36-89](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/server.ts#L36-L89)

## Entry point and error conventions

### Page and Layout Component Parameter Validation

The language service plugin validates entry point components by inspecting the parameters of default export function declarations in page and layout files. For page entries determined via `isPageFile`, parameters are restricted to `params` and `searchParams`. For layout entries, the plugin reads the current directory using `fs.readdirSync` with `withFileTypes: true` to discover any directory names starting with `@`, which represent parallel route slots. These slot names are sliced and appended to the allowed layout properties.
Sources: [packages/next/src/server/typescript/rules/entry.ts:13-58](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/entry.ts#L13-L58), [packages/next/src/server/typescript/rules/entry.ts:112-139](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/entry.ts#L112-L139)

When semantic diagnostics are evaluated for an entry component, the plugin iterates over object binding pattern elements in the function parameters. If an element name is not included in the valid properties list, a diagnostic error is pushed with code `NEXT_TS_ERRORS.INVALID_PAGE_PROP` and message text specifying that the property is not a valid page or layout prop.
Sources: [packages/next/src/server/typescript/rules/entry.ts:112-161](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/entry.ts#L112-L161)

```typescript
const diagnostics: tsModule.Diagnostic[] = []

const props = node.parameters?.[0]?.name
if (props && ts.isObjectBindingPattern(props)) {
  for (const prop of props.elements) {
    const propName = (prop.propertyName || prop.name).getText()
    if (!validProps.includes(propName)) {
      diagnostics.push({
        file: source,
        category: ts.DiagnosticCategory.Error,
        code: NEXT_TS_ERRORS.INVALID_PAGE_PROP,
        messageText: `"${propName}" is not a valid ${type} prop.`,
        start: prop.getStart(),
        length: prop.getWidth(),
      })
    }
  }
}

return diagnostics
```
Sources: [packages/next/src/server/typescript/rules/entry.ts:141-160](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/entry.ts#L141-L160)

> [!WARNING]
> Using an unrecognized identifier inside page or layout destructuring patterns triggers an `INVALID_PAGE_PROP` error diagnostic at the exact start and width of the offending property node.
> Sources: [packages/next/src/server/typescript/rules/entry.ts:143-157](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/entry.ts#L143-L157)

### Error Boundary Client Directive Enforcement

The error entry rule module inspects files matching the pattern `error.tsx?` or `global-error.tsx?` to enforce that error boundaries are designated client components. If the `isClientEntry` flag passed to `getSemanticDiagnostics` is false, the plugin immediately returns a diagnostic error for the entire file.
Sources: [packages/next/src/server/typescript/rules/error.ts:7-34](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/error.ts#L7-L34)

```typescript
if (!isClientEntry) {
  // Error components must be Client Components
  return [
    {
      file: source,
      category: ts.DiagnosticCategory.Error,
      code: NEXT_TS_ERRORS.INVALID_ERROR_COMPONENT,
      messageText: `Error Components must be Client Components, please add the "use client" directive: https://nextjs.org/docs/app/api-reference/file-conventions/error`,
      start: 0,
      length: source.text.length,
    },
  ]
}
```
Sources: [packages/next/src/server/typescript/rules/error.ts:19-31](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/error.ts#L19-L31)

> [!CAUTION]
> Error and global-error components missing the `"use client"` directive receive diagnostic code `NEXT_TS_ERRORS.INVALID_ERROR_COMPONENT`, forcing developers to explicitly convert them into Client Components.
> Sources: [packages/next/src/server/typescript/rules/error.ts:19-30](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/error.ts#L19-L30)

### Metadata Typing and Export Restrictions

The metadata rule module handles semantic validation for `metadata` and `generateMetadata` exports across both client and server boundaries. In client entries, exporting either symbol via variable statements, function declarations, or export declarations results in `NEXT_TS_ERRORS.INVALID_METADATA_EXPORT` errors stating that these APIs are forbidden in Client Components.
Sources: [packages/next/src/server/typescript/rules/metadata.ts:6-74](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/metadata.ts#L6-L74)

In server entries, the plugin checks whether `metadata` or `generateMetadata` exports carry proper type annotations using the helper function `hasType`. If a server component exports `generateMetadata` or `metadata` without an explicit return type or variable type annotation, a warning diagnostic is generated recommending the appropriate `Metadata` or `Promise<Metadata>` type from `"next"`.
Sources: [packages/next/src/server/typescript/rules/metadata.ts:75-242](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/metadata.ts#L75-L242), [packages/next/src/server/typescript/rules/metadata.ts:244-281](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/metadata.ts#L244-L281)

```typescript
function hasType(node: tsModule.Declaration): boolean {
  const ts = getTs()

  if (
    !ts.isVariableDeclaration(node) &&
    !ts.isFunctionDeclaration(node) &&
    !ts.isArrowFunction(node) &&
    !ts.isFunctionExpression(node)
  ) {
    return false
  }

  // For function declarations, expressions, and arrow functions, check if they have return type
  if (
    ts.isFunctionDeclaration(node) ||
    ts.isFunctionExpression(node) ||
    ts.isArrowFunction(node)
  ) {
    return !!node.type
  }

  // For variable declarations
  if (!node.name) return false
  const name = node.name.getText()
  if (name === 'generateMetadata') {
    // If it's a function expression or arrow function, check if it has return type
    if (
      node.initializer &&
      (ts.isFunctionExpression(node.initializer) ||
        ts.isArrowFunction(node.initializer))
    ) {
      return !!node.initializer.type
    }
  }

  // For all other cases, check if the node has a type annotation
  return !!node.type
}
```
Sources: [packages/next/src/server/typescript/rules/metadata.ts:244-281](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/metadata.ts#L244-L281)

> [!NOTE]
> The `hasType` utility inspects function return types or variable initializers to verify explicit type annotations on metadata declarations before deciding whether to emit type warnings.
> Sources: [packages/next/src/server/typescript/rules/metadata.ts:244-281](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/server/typescript/rules/metadata.ts#L244-L281)

## Build typegen and configuration verification

### Next Types Plugin Artifact Generation and Route Typing

During compilation, Next.js generates TypeScript artifacts inside the `.next/types` directory to validate layouts, pages, and [route handlers](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/server-runtime/route-handlers). The `NextTypesPlugin` creates type-guard files that import entry modules and verify their exported fields, parameters, and return types against strict schema definitions using the `checkFields` and `Diff` utility types.
Sources: [packages/next/src/build/webpack/plugins/next-types-plugin/index.ts:11-88](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts#L11-L88)

```typescript
function createTypeGuardFile(
  fullPath: string,
  relativePath: string,
  options: {
    type: 'layout' | 'page' | 'route'
    slots?: string[]
  }
) {
  return `// File: ${fullPath}
import * as entry from '${relativePath}.js'
${
  options.type === 'route'
    ? `import type { NextRequest } from 'next/server.js'`
    : `import type { ResolvingMetadata, ResolvingViewport } from 'next/dist/lib/metadata/types/metadata-interface.js'`
}

import type { InstantConfigForTypeCheckInternal, Prefetch, EnsureStatic } from 'next/dist/build/segment-config/app/app-segment-config.js'

type TEntry = typeof import('${relativePath}.js')

type SegmentParams<T extends Object = any> = T extends Record<string, any>
  ? { [K in keyof T]: T[K] extends string ? string | string[] | undefined : never }
  : T

// Check that the entry is a valid entry
checkFields<Diff<{
  ${
    options.type === 'route'
      ? HTTP_METHODS.map((method) => `${method}?: Function`).join('\n  ')
      : 'default: Function'
  }
  config?: {}
  generateStaticParams?: Function
  ${options.type === 'route' ? '' : 'unstable_paramMatching?: {}\n  unstable_generateParamMatching?: Function'}
  instant?: InstantConfigForTypeCheckInternal
  prefetch?: Prefetch
  ensureStatic?: EnsureStatic
  unstable_dynamicStaleTime?: number
  revalidate?: RevalidateRange<TEntry> | false
  dynamic?: 'auto' | 'force-dynamic' | 'error' | 'force-static'
  dynamicParams?: boolean
  fetchCache?: 'auto' | 'force-no-store' | 'only-no-store' | 'default-no-store' | 'default-cache' | 'only-cache' | 'force-cache'
  /** @deprecated The \`preferredRegion\` config is deprecated. Remove this export. */
  preferredRegion?: 'auto' | 'global' | 'home' | string | string[]
  runtime?: 'nodejs' | 'experimental-edge' | 'edge'
  maxDuration?: number
  ${
    options.type === 'route'
      ? ''
      : `
  metadata?: any
  generateMetadata?: Function
  viewport?: any
  generateViewport?: Function
  `
  }
}, TEntry, ''>>()

```
Sources: [packages/next/src/build/webpack/plugins/next-types-plugin/index.ts:31-88](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts#L31-L88)

For [App Router](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/client-runtime/app-router) route handlers, the type generator verifies that HTTP methods receive a `Request` or `NextRequest` as their first argument and a `RouteContext` containing `params` as their second argument, while returning a `Response`, `void`, `never`, or a Promise resolving to them. For pages and layouts, it checks `PageProps` and `LayoutProps` alongside `generateStaticParams`, `generateMetadata`, and `generateViewport`.
Sources: [packages/next/src/build/webpack/plugins/next-types-plugin/index.ts:89-180](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts#L89-L180)

```typescript
    : `// Check the prop type of the entry function
checkFields<Diff<${
        options.type === 'page' ? 'PageProps' : 'LayoutProps'
      }, FirstArg<TEntry['default']>, 'default'>>()

// Check the arguments and return type of the generateMetadata function
if ('generateMetadata' in entry) {
  checkFields<Diff<${
    options.type === 'page' ? 'PageProps' : 'LayoutProps'
  }, FirstArg<MaybeField<TEntry, 'generateMetadata'>>, 'generateMetadata'>>()
  checkFields<Diff<ResolvingMetadata, SecondArg<MaybeField<TEntry, 'generateMetadata'>>, 'generateMetadata'>>()
}

// Check the arguments and return type of the generateViewport function
if ('generateViewport' in entry) {
  checkFields<Diff<${
    options.type === 'page' ? 'PageProps' : 'LayoutProps'
  }, FirstArg<MaybeField<TEntry, 'generateViewport'>>, 'generateViewport'>>()
  checkFields<Diff<ResolvingViewport, SecondArg<MaybeField<TEntry, 'generateViewport'>>, 'generateViewport'>>()
}
`
}
// Check the arguments and return type of the generateStaticParams function
if ('generateStaticParams' in entry) {
  checkFields<Diff<{ params: SegmentParams }, FirstArg<MaybeField<TEntry, 'generateStaticParams'>>, 'generateStaticParams'>>()
  checkFields<Diff<{ __tag__: 'generateStaticParams', __return_type__: any[] | Promise<any[]> }, { __tag__: 'generateStaticParams', __return_type__: ReturnType<MaybeField<TEntry, 'generateStaticParams'>> }>>()
}

export interface PageProps {
  params?: Promise<SegmentParams>
  searchParams?: Promise<any>
}
export interface LayoutProps {
  children?: React.ReactNode
${
  options.slots
    ? options.slots.map((slot) => `  ${slot}: React.ReactNode`).join('\n')
    : ''
}
  params?: Promise<SegmentParams>
}

```
Sources: [packages/next/src/build/webpack/plugins/next-types-plugin/index.ts:139-180](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts#L139-L180)

> [!WARNING]
> When route or page exports violate expected type constraints, diagnostic formatter rules intercept TypeScript error code `2344` and translate raw type failures into readable developer messages identifying the exact file path and invalid export field.
> Sources: [packages/next/src/lib/typescript/diagnosticFormatter.ts:54-190](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/lib/typescript/diagnosticFormatter.ts#L54-L190)

### Tsconfig Verification and Configuration Defaults

The setup verification pipeline inspects the project's `tsconfig.json` file, automatically writing configuration defaults and injecting required compiler options and plugins via `writeConfigurationDefaults`. If a user project extends an external configuration or specifies explicit paths, the setup utility adapts or warns about manual steps.
Sources: [packages/next/src/lib/verify-typescript-setup.ts:231-252](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/lib/verify-typescript-setup.ts#L231-L252), [packages/next/src/lib/typescript/writeConfigurationDefaults.ts:205-240](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/lib/typescript/writeConfigurationDefaults.ts#L205-L240)

```typescript
export async function writeConfigurationDefaults(
  typescriptVersion: string,
  tsConfigPath: string,
  isFirstTimeSetup: boolean,
  hasAppDir: boolean,
  distDir: string,
  hasPagesDir: boolean,
  strictRouteTypes: boolean
): Promise<void> {
  if (isFirstTimeSetup) {
    writeFileSync(tsConfigPath, '{}' + os.EOL)
  }

  const userTsConfigContent = readFileSync(tsConfigPath, 'utf8')
  const userTsConfig = CommentJson.parse(userTsConfigContent)

  // Bail automatic setup when the user has extended or referenced another config
  if ('extends' in userTsConfig || 'references' in userTsConfig) {
    return
  }

  if (userTsConfig?.compilerOptions == null) {
    userTsConfig.compilerOptions = {}
    isFirstTimeSetup = true
  }

  const desiredCompilerOptions = getDesiredCompilerOptions(
    typescriptVersion,
    userTsConfig
  )

  const suggestedActions: string[] = []
  const requiredActions: string[] = []
  for (const optionKey in desiredCompilerOptions) {
    const check = desiredCompilerOptions[optionKey]
    if ('suggested' in check) {
```
Sources: [packages/next/src/lib/typescript/writeConfigurationDefaults.ts:205-240](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/lib/typescript/writeConfigurationDefaults.ts#L205-L240)

The desired compiler options shape enforces specific values for module resolution, target, JSX runtime, and incremental compilation to match Next.js SWC and webpack build semantics. The table below lists the required and suggested compiler options enforced or injected by the configuration utility:

| Option Key | Setting Type | Target Value / Suggested | Purpose / Reason |
| :--- | :--- | :--- | :--- |
| `target` | Suggested | `ES2017` | For top-level `await` support |
| `lib` | Suggested | `['dom', 'dom.iterable', 'esnext']` | Standard browser and ECMAScript libraries |
| `allowJs` | Suggested | `true` | Allow JavaScript file compilation |
| `skipLibCheck` | Suggested | `true` | Skip type checking of declaration files |
| `strict` | Suggested | `false` | Default strictness level for user projects |
| `noEmit` | Suggested | `true` | Do not emit outputs during type checking |
| `incremental` | Suggested | `true` | Enable incremental compilation |
| `module` | Required | `esnext` | Required for dynamic `import()` support |
| `esModuleInterop` | Required | `true` | Requirement for SWC and Babel interoperability |
| `moduleResolution` | Required | `bundler` or `node` | Matches modern bundler or webpack resolution |
| `resolveJsonModule` | Required | `true` | Matches webpack resolution for JSON modules |
| `isolatedModules` | Required | `true` | Requirement for SWC and Babel transpilation |
| `jsx` | Required | `react-jsx` | Next.js uses the React automatic runtime |

Sources: [packages/next/src/lib/typescript/writeConfigurationDefaults.ts:52-144](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/lib/typescript/writeConfigurationDefaults.ts#L52-L144)

> [!IMPORTANT]
> If a configuration file contains an `extends` or `references` property, automatic modification of `plugins` and compiler options is bypassed to prevent overriding parent configurations.
> Sources: [packages/next/src/lib/typescript/writeConfigurationDefaults.ts:221-224](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/lib/typescript/writeConfigurationDefaults.ts#L221-L224), [packages/next/src/lib/typescript/writeConfigurationDefaults.ts:345-352](https://github.com/blade47/next.js/blob/d8c1c1b0002db8ccb63b58095f338e8bf423fa99/packages/next/src/lib/typescript/writeConfigurationDefaults.ts#L345-L352)

## Related

- [Build Pipeline](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/technical/build-system/build-pipeline)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/8f4009b0-65bd-4480-9b00-e201f0914bb3/llms.txt) for all pages in this wiki.
