# impound

> Builder-agnostic plugin to allow restricting import patterns in certain parts of your code-base.

Latest version **1.2.0** (published 2026-08-25) · MIT license · 0 weekly downloads

## Install

```sh
npm install impound
pnpm add impound
yarn add impound
bun add impound
```

## Health

**Score 75/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; has provenance; recently updated; high maintenance score; high quality score.

Warnings: low downloads.

## Facts

| | |
|---|---|
| Version | 1.2.0 |
| Published | 2026-08-25 |
| First published | 2024-08-29 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 5 |
| Unpacked size | 33 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 88 |
| Maintainers | danielroe |

## Links

- npm: https://www.npmjs.com/package/impound
- Repository: https://github.com/unjs/impound
- Homepage: https://github.com/unjs/impound#readme
- Issues: https://github.com/unjs/impound/issues
- npm.io page: https://npm.io/package/impound

## Dependencies (5)

- [pathe](https://npm.io/package/pathe.md) ^2.0.3
- [unplugin](https://npm.io/package/unplugin.md) ^3.0.0
- [unplugin-utils](https://npm.io/package/unplugin-utils.md) ^0.3.1
- [es-module-lexer](https://npm.io/package/es-module-lexer.md) ^2.0.0
- [@jridgewell/trace-mapping](https://npm.io/package/@jridgewell/trace-mapping.md) ^0.3.31

## Recent versions

- 1.2.0 (latest) — 2026-08-25
- 1.1.7 — 2026-08-14
- 1.1.6 — 2026-07-23
- 1.1.5 — 2026-03-09
- 1.1.4 — 2026-03-09
- 1.1.3 — 2026-03-09
- 1.1.2 — 2026-03-05
- 1.1.1 — 2026-03-05
- 1.1.0 — 2026-03-05
- 1.0.0 — 2025-04-21
- 0.2.2 — 2025-03-09
- 0.2.1 — 2025-03-08
- 0.2.0 — 2024-10-10
- 0.1.0 — 2024-08-29
- 0.0.0 — 2024-08-29

## README

# impound

[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![Github Actions][github-actions-src]][github-actions-href]
[![Codecov][codecov-src]][codecov-href]

> Build plugin to restrict import patterns in certain parts of your code-base.

This package is an [unplugin](https://unplugin.unjs.io/) which provides support for a wide range of bundlers.

## Usage

Install package:

```sh
# npm
npm install impound
```

```js
// rollup.config.js
import { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { ImpoundPlugin } from 'impound'

export default {
  plugins: [
    ImpoundPlugin.rollup({
      cwd: dirname(fileURLToPath(import.meta.url)),
      include: [/src\/*/],
      patterns: [
        [/^node:.*/], // disallows all node imports
        ['@nuxt/kit', 'Importing from @nuxt/kit is not allowed in your src/ directory'], // custom error message
        [(id, importer) => id.endsWith('.server') && `Server-only import in ${importer}`] // functional pattern with importer context
      ]
    }),
  ],
}
```

### Import Tracing

Enable `trace: true` to get rich violation diagnostics with full import chains and code snippets. When enabled, errors are deferred to `buildEnd` so the complete module graph can be collected first.

```js
ImpoundPlugin.rollup({
  cwd: dirname(fileURLToPath(import.meta.url)),
  trace: true,
  patterns: [
    [/\.server$/, 'Server-only import', ['Use a server function instead', 'Move this import to a .server.ts file']]
  ]
})
```

Example output:

```text
Invalid import [importing `secret` from `middle.js`]

Trace:
  1. src/routes/index.tsx:2:34 (entry) (import "../features/auth/session")
  2. src/features/auth/session.ts

Code:
  1 | import { logger } from '../utils/logger'
  2 |
> 3 | import { getUsers } from '../db/queries.server'
    |                           ^
  4 |
  5 | export function loadAuth() {

Suggestions:
  - Use a server function instead
  - Move this import to a .server.ts file
```

#### Choosing a trace mode

`trace: true` records the import graph as modules are transformed. Every module gets
parsed, and modules an `include` pattern covers also get their sourcemap built and their
source retained, so snippets can point at original source.

A narrow `include` therefore keeps eager tracing cheap: only modules that could be the
importer in a violation are retained.

`trace: 'lazy'` records nothing, and reads the bundler's own module graph when a
violation actually happens.

|  | `true` | `'lazy'` |
|---|---|---|
| Import chain | yes | yes, including dynamic imports |
| Code snippet | yes | yes |
| Snippet shows | original source | original source on webpack and rspack, otherwise the code the bundler holds |
| Per-module cost | parse, plus sourcemap + retain within `include` | none |
| Bundlers | all | all except esbuild |

Lazy reports from `buildEnd`, and a dev server only calls that when it shuts down, so
keep `true` for dev:

```js
ImpoundPlugin.vite({
  trace: isDev ? true : 'lazy',
  patterns: [[/\.server$/, 'Server-only import']]
})
```

Lazy reads the graph through `getModuleInfo` on rollup, vite and rolldown, and through
`compilation.moduleGraph` on webpack and rspack, where the snippet comes from
`originalSource()` and so shows original rather than transformed code. esbuild exposes
no module graph to a plugin, so there lazy reports the plain message with no chain or
snippet.

With `error: true`, lazy reports the first violation and fails the build there, so later
ones stay unreported until it is fixed. With either mode, `onViolation` returning `false`
suppresses the report but no longer allows the import: by the time the hook runs, the
import has already been replaced by the proxy.

### Named imports from a denied module

A denied import is replaced by a proxy module that has only a default export.
`syntheticNamedExports` papers over that on Rollup alone: rolldown, webpack, rspack and
esbuild ignore it. So on those, a named import from a denied module can fail with an
error naming `impound:proxy` before impound reports the real violation. It shows up only
when the build is allowed to continue past a violation, which means `error: false` or
lazy tracing.

## 💻 Development

- Clone this repository
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
- Install dependencies using `pnpm install`
- Run interactive tests using `pnpm dev`

## Acknowledgements

Some features in impound were inspired by [TanStack Start's import protection](https://tanstack.com/start/latest/docs/framework/react/guide/import-protection).

## License

Made with ❤️

Published under [MIT License](./LICENCE).

<!-- Badges -->

[npm-version-src]: https://npmx.dev/api/registry/badge/version/impound
[npm-version-href]: https://npmx.dev/package/impound
[npm-downloads-src]: https://npmx.dev/api/registry/badge/downloads/impound
[npm-downloads-href]: https://npm.chart.dev/impound
[github-actions-src]: https://img.shields.io/github/actions/workflow/status/unjs/impound/ci.yml?branch=main&style=flat-square
[github-actions-href]: https://github.com/unjs/impound/actions?query=workflow%3Aci
[codecov-src]: https://img.shields.io/codecov/c/gh/unjs/impound/main?style=flat-square
[codecov-href]: https://codecov.io/gh/unjs/impound

---
_Source: https://npm.io/package/impound · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
