# Next.js plugin

Source: https://permdock.com/docs/cli/next-plugin

createPermDockPlugin runs permdock collect during next dev and next build; it is a build hook only and never wires the PermDock API.

`createPermDockPlugin` is exported from `permdock/next/plugin` and wraps `next.config.ts`. Its only job is to run [collect](/docs/cli/collect) while Next.js runs, the way next-intl's loader keeps extracted message catalogs in sync during development. It does not alias modules, does not augment types and does not create a `PermDock` instance. API wiring is the explicit factory file described in the [quick start](/docs/getting-started/quick-start).

## Usage [#usage]

```ts
// next.config.ts
import { createPermDockPlugin } from "permdock/next/plugin";

const permdockPlugin = createPermDockPlugin({
  collect: { srcPath: ["./src", "../ui/src", "./node_modules/@acme/*"] },
});

export default permdockPlugin({
  // your Next.js config
});
```

`srcPath` accepts first-party folders, sibling workspace packages and installed packages, so a monorepo where `@acme/ui` ships its own `permissions.ts` next to its components is collected into the app's catalog without any manual import.

`permdockPlugin` accepts a config object or a config function and returns Next's config function `(phase, context) => Promise<config>`: the phase constant is how the plugin tells `next build` from `next dev`. Put it outermost when composing with plugins that only accept an object:

```ts
export default permdockPlugin(withOtherPlugin({/* your Next.js config */}));
```

## What it does [#what-it-does]

| Phase | Behaviour |
| --- | --- |
| `next dev` | Runs `collect` once at startup, then watches each app root the way [`collect --watch`](/docs/cli/collect) does: `srcPath`, the config file and the configured modules, ignoring its own outputs. Writes `permissions.catalog.json` (and the barrel when `collect.barrel` is enabled). Failures are logged, never fatal. |
| `next build` | Runs `collect --check`. A stale catalog fails the build with the diff, so a deployment can never ship a catalog that disagrees with the code. `PERMDOCK_COLLECT=write` switches to writing instead of checking for build pipelines that commit generated files. |
| `next start`, `next export` | Nothing. |

The plugin runs `collect` in-process from the same `permdock` package the app already depends on, so there is nothing else to install.

## What it does not do [#what-it-does-not-do]

* It does not provide `getPermDock`, `getPermission` or `usePermission`. Those come from your factory file and from `permdock/react`.
* It does not add a webpack or Turbopack alias for a request config module.
* It does not augment `permdock` types with your policy or subject.
* It does not run `usage`, `doctor` or `openapi`; those stay explicit CI steps.

This is deliberate. The alternative, a next-intl-style plugin plus request config plus module augmentation, would have given a package-level import for server helpers at the cost of being Next-only and global to one policy per app. Explicit factories work identically in Vite, Expo and Hono, and agents follow one recipe.

Vite apps use [`createPermDockUnplugin`](/docs/cli/unplugin) for the same hook. Expo (Metro) has no build hook; run `permdock collect` as a script instead.

## Options [#options]

```ts
createPermDockPlugin({
  collect: {
    srcPath: string[]          // required; globs relative to the app root
    out?: string               // default 'permissions.catalog.json'
    barrel?: boolean | string  // default false; true writes src/permissions.generated.ts
  },
  onDrift?: 'error' | 'warn'   // build behaviour on a stale catalog; default 'error'
  check?: boolean              // unplugin only: check instead of write in buildStart; default false
})
```

Settings can also live in `permdock.config.ts`; plugin options override the file.

## Turbopack [#turbopack]

Next.js 16.3 builds with Turbopack by default. The plugin does not register a loader or a Turbopack rule; it hooks Next's config lifecycle and runs the collector as a side process, so it works with Turbopack and webpack alike and has no effect on the module graph or on the App Shell used by Instant Navigations ([Next.js 16.3 research](/docs/guides/next-cache-components#why-this-shape)).

## Example [#example]

`apps/examples/next` uses the plugin. `apps/examples/monorepo` collects from two sibling feature packages with `permdock collect --check` and fails CI on catalog drift.

## Why [#why]

* **The dev-time catalog stays at the app root, not in `.next/`.** The catalog is a committed file that `collect --check` compares in CI, that `permdock usage`, `openapi` and `cloud push` read, and that reviewers see in a diff. Writing it into `.next/` during `next dev` would give the same data two homes, one of them deleted by every `next build` and invisible to tools that do not know about Next.js.

## Related [#related]

* [unplugin](/docs/cli/unplugin)
* [collect](/docs/cli/collect)
* [Next.js adapter](/docs/adapters/next)
* [Larger apps](/docs/getting-started/larger-apps)
* [next-intl extraction model](/docs/cli/collect#why-this-model)
