---
title: "Migrating to Mandu 0.28 — __generated__ imports now hard-fail"
description: "Issue #207 — the mandu:block-generated-imports bundler plugin is installed by default."
order: 3
---

# 0.28 — `__generated__/` imports now hard-fail at build time

## What changed

Mandu 0.28 ships a Bun bundler plugin, `mandu:block-generated-imports`,
installed by default on every `mandu dev`, `mandu build`, and `mandu start`
run. The plugin rejects any import whose specifier contains `__generated__`
with a structured, actionable error.

Previously, direct `__generated__/` imports were caught only by
`mandu guard check`, which most users ran in CI (not locally) and
autonomous coding agents routinely bypassed. The bundler-level plugin
makes direct imports **physically impossible** to build.

## Who is affected

Any source file matching:

```ts
import x from "./__generated__/foo";         // ❌ blocked
import x from "../../src/__generated__/foo"; // ❌ blocked
import x from "~/shared/__generated__/foo";  // ❌ blocked
```

Unaffected:

```ts
import { getGenerated } from "@mandujs/core/runtime"; // ✅ supported
const data = getGenerated("routes");                  // ✅ supported

import type { X } from "./__generated__/foo"; // ✅ erased by TS before bundle
// (In practice this only reaches the bundler via a value-preserving import
//  idiom; the type-only form never triggers the plugin.)
```

## How to fix

Replace the direct import with the runtime registry.

**Before:**

```ts
import { routes } from "./__generated__/routes";

for (const r of routes) console.log(r.id);
```

**After:**

```ts
import { getGenerated } from "@mandujs/core/runtime";

const manifest = getGenerated("routes");
for (const r of manifest.routes) console.log(r.id);
```

See [`docs/architect/generated-access.md`](../architect/generated-access.md)
for the full decision tree, including `tryGetGenerated()` for optional
artifacts and `registerManifest()` for tests.

## Error message shape

```text
Direct __generated__/ imports are forbidden: ./__generated__/routes.
Use the runtime registry: see https://mandujs.com/docs/architect/generated-access
  Importer: /your-repo/src/app/page.tsx
  Replacement: import { getGenerated } from "@mandujs/core/runtime";
  Then: const data = getGenerated(<key>);
  Docs: https://mandujs.com/docs/architect/generated-access
```

The bundler surface shows this message in the `result.logs[]` array that
`mandu dev` / `mandu build` prints on failure. The `ForbiddenGeneratedImportError`
class is also exported from `@mandujs/core/bundler/plugins` for tests.

## Opt-out

Emergency escape hatch — set in `mandu.config.ts`:

```ts
export default {
  guard: {
    blockGeneratedImport: false, // default: true
  },
};
```

This disables the plugin on all bundler call-sites. The static Guard
rule `INVALID_GENERATED_IMPORT` still flags the pattern during
`mandu guard check` — opting out of the bundler layer does not disable
the lint layer.

There is also an undocumented env escape hatch,
`MANDU_DISABLE_BUNDLER_PLUGINS=1`, which disables **all** Mandu default
plugins on the SSR bundler path. Use only when a genuine Bun bundler
regression blocks you.

## Templates

New projects created via `mandu init` get a `tsconfig.json` `paths`
entry that surfaces the error as a TypeScript compile error at edit
time — three layers of defence total (IDE, static guard, bundler).
Existing projects are unaffected; they still get the bundler-level
enforcement but not the IDE-level feedback.

## References

- Issue: [#207](https://github.com/konamgil/mandu/issues/207)
- Docs: [`docs/architect/generated-access.md`](../architect/generated-access.md)
- Source: `packages/core/src/bundler/plugins/block-generated-imports.ts`
- Config schema: `packages/core/src/config/validate.ts` (`GuardConfigSchema`)
