> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fallow.tools/llms.txt
> Use this file to discover all available pages before exploring further.

# Architecture boundaries

> Enforce architecture rules with directory-based import boundaries. Define zones for UI, data, and shared code. Fallow catches violations at Rust speed.

`fallow dead-code` enforces architecture boundaries by checking that imports between directories follow your rules. Define <Tooltip tip="Named groups of files matched by glob patterns, e.g., 'ui' matches src/components/**">zones</Tooltip> and declare which zones may import from which.

```bash theme={null}
fallow dead-code --boundary-violations
```

<Info>
  Boundary violations are included in `fallow dead-code` output by default. Use `--boundary-violations` to show only boundary issues.
</Info>

## Quick start with presets

The fastest way to add boundaries is with a built-in preset. Fallow ships four presets for common architecture patterns:

<CodeGroup>
  ```jsonc .fallowrc.json theme={null}
  {
    "boundaries": {
      "preset": "bulletproof"
    }
  }
  ```

  ```toml fallow.toml theme={null}
  [boundaries]
  preset = "bulletproof"
  ```
</CodeGroup>

Run `fallow list --boundaries` to see the expanded zones and rules:

```bash title="$ fallow list --boundaries" theme={null}
Boundaries: 5 zones, 5 rules

Zones:
  app                  3 files  src/app/**
  features/auth        7 files  src/features/auth/**
  features/billing     5 files  src/features/billing/**
  shared               8 files  src/components/**, src/hooks/**, src/lib/**, ...
  server               4 files  src/server/**

Rules:
  app                  → features/auth, features/billing, shared, server
  features/auth        → shared, server
  features/billing     → shared, server
  server               → shared
  shared               (isolated — no imports allowed)
```

## Presets

<Tabs>
  <Tab title="Bulletproof">
    A widely used React/Next.js pattern. Feature modules are isolated from each other; shared utilities and server infrastructure form the base layers.

    **4 logical zones:** `app`, `features`, `shared`, `server`. The `features` zone auto-discovers immediate child directories so sibling features are isolated as `features/<name>` zones. Top-level files inside `src/features/` (barrels, shared types) fall back to the parent `features` zone; the parent rule automatically allows discovered children, so barrels can re-export features without false positives while non-barrel top-level files still obey the `features` rule.

    ```
    app              → every feature, shared, server
    features/<name>  → shared, server
    server           → shared
    shared           (isolated)
    ```

    The `shared` zone covers: `components`, `hooks`, `lib`, `utils`, `utilities`, `providers`, `shared`, `types`, `styles`, `i18n`.

    <Tip>
      This preset matches the architecture from [Bulletproof React](https://github.com/alan2207/bulletproof-react) and is the most common pattern in modern React and Next.js projects.
    </Tip>
  </Tab>

  <Tab title="Layered">
    Classic N-tier architecture with four layers. Infrastructure may import from both domain and application (common for dependency injection).

    **4 zones:** `presentation`, `application`, `domain`, `infrastructure`

    ```
    presentation    → application
    application     → domain
    domain          (isolated)
    infrastructure  → domain, application
    ```
  </Tab>

  <Tab title="Hexagonal">
    Ports and adapters pattern. The domain has zero outward dependencies; adapters implement port interfaces.

    **3 zones:** `adapters`, `ports`, `domain`

    ```
    adapters  → ports
    ports     → domain
    domain    (isolated)
    ```
  </Tab>

  <Tab title="Feature-Sliced">
    [Feature-Sliced Design](https://fsd.how/) with strict downward-only imports. Each layer may only import from layers below it.

    **6 zones:** `app`, `pages`, `widgets`, `features`, `entities`, `shared`

    ```
    app       → pages, widgets, features, entities, shared
    pages     → widgets, features, entities, shared
    widgets   → features, entities, shared
    features  → entities, shared
    entities  → shared
    shared    (isolated)
    ```
  </Tab>
</Tabs>

### Source root detection

Preset zone patterns use `{rootDir}/{zone}/**`. Fallow auto-detects the source root from `tsconfig.json`:

```jsonc title="tsconfig.json" theme={null}
{
  "compilerOptions": {
    "rootDir": "./lib"  // zones become lib/app/**, lib/features/**, etc.
  }
}
```

If no `rootDir` is found, fallow falls back to `src`.

## Custom zones and rules

For full control, define zones and rules directly:

<CodeGroup>
  ```jsonc .fallowrc.json theme={null}
  {
    "boundaries": {
      "zones": [
        { "name": "ui", "patterns": ["src/components/**", "src/pages/**"] },
        { "name": "data", "patterns": ["src/db/**", "src/api/**"] },
        { "name": "shared", "patterns": ["src/lib/**", "src/utils/**"] }
      ],
      "rules": [
        { "from": "ui", "allow": ["shared"] },
        { "from": "data", "allow": ["shared"] },
        { "from": "shared", "allow": [] }
      ]
    }
  }
  ```

  ```toml fallow.toml theme={null}
  [[boundaries.zones]]
  name = "ui"
  patterns = ["src/components/**", "src/pages/**"]

  [[boundaries.zones]]
  name = "data"
  patterns = ["src/db/**", "src/api/**"]

  [[boundaries.zones]]
  name = "shared"
  patterns = ["src/lib/**", "src/utils/**"]

  [[boundaries.rules]]
  from = "ui"
  allow = ["shared"]

  [[boundaries.rules]]
  from = "data"
  allow = ["shared"]

  [[boundaries.rules]]
  from = "shared"
  allow = []
  ```
</CodeGroup>

### How zones work

* A file belongs to the **first zone** whose pattern matches (first-match wins)
* Files that don't match any zone are **unrestricted**: they can import from and be imported by any zone
* **Self-imports** are always allowed (files in the same zone can freely import each other)
* A zone with **no rule entry** is unrestricted: it can import from any zone
* A zone with a rule and an **empty `allow` list** is isolated: it cannot import from other zones

### Auto-discovered feature zones

Use `autoDiscover` when one logical zone should create one concrete zone per child directory. This is useful for feature-module architectures where `src/features/auth` and `src/features/billing` should be isolated from each other without writing a zone and rule for every feature.

```jsonc theme={null}
{
  "boundaries": {
    "zones": [
      { "name": "app", "patterns": ["src/app/**"] },
      { "name": "features", "patterns": ["src/features/**"], "autoDiscover": ["src/features"] },
      { "name": "shared", "patterns": ["src/shared/**"] }
    ],
    "rules": [
      { "from": "app", "allow": ["features", "shared"] },
      { "from": "features", "allow": ["shared"] }
    ]
  }
}
```

If `src/features/auth` and `src/features/billing` exist, fallow expands this to `features/auth` and `features/billing`. Rules that reference the logical `features` parent apply to every discovered feature. Explicit child rules, such as `from: "features/auth"`, override generated parent rules.

When the zone also has `patterns`, discovered children classify first and top-level files inside the auto-discover directory fall back to the parent zone. The parent fallback rule automatically allows discovered children, so a `src/features/index.ts` barrel can re-export feature modules while non-barrel top-level files such as `src/features/types.ts` still obey the parent `features` rule. Generated child rules keep the original `allow` list exactly, so sibling-feature isolation stays intact. Omit `patterns` to leave top-level files unrestricted.

### Subtree scope (`root`)

Monorepos with per-package boundaries usually have the same internal directory layout under each package (`packages/app/src/`, `packages/core/src/`, ...). Writing flat patterns from the project root forces zone definitions to scale with the cross product of (zones, packages):

```jsonc theme={null}
// Without `root`: one zone per (layer, package) pair.
{ "name": "ui-app",      "patterns": ["packages/app/src/**"] },
{ "name": "domain-core", "patterns": ["packages/core/src/**"] }
```

Set `root` on a zone to scope its patterns to a subtree. At classification time, fallow checks that the file's path starts with the `root` prefix and strips that prefix before matching the patterns against the remainder. Files outside the subtree never match the zone.

<CodeGroup>
  ```jsonc .fallowrc.json theme={null}
  {
    "boundaries": {
      "zones": [
        { "name": "ui",     "patterns": ["src/**"], "root": "packages/app/" },
        { "name": "domain", "patterns": ["src/**"], "root": "packages/core/" }
      ],
      "rules": [
        { "from": "ui", "allow": [] }
      ]
    }
  }
  ```

  ```toml fallow.toml theme={null}
  [[boundaries.zones]]
  name = "ui"
  patterns = ["src/**"]
  root = "packages/app/"

  [[boundaries.zones]]
  name = "domain"
  patterns = ["src/**"]
  root = "packages/core/"

  [[boundaries.rules]]
  from = "ui"
  allow = []
  ```
</CodeGroup>

In this example, `packages/app/src/login.tsx` classifies as `ui` and `packages/core/src/order.ts` classifies as `domain`. Adding `packages/billing/` later only requires another zone entry with the same `patterns: ["src/**"]` and a different `root`.

Trailing slashes and a leading `./` are normalized for you, so `"packages/app"`, `"packages/app/"`, and `"./packages/app/"` are equivalent. Backslashes are converted to forward slashes.

<Warning>
  Patterns must NOT redundantly include the root prefix. `root: "packages/app/"` paired with `patterns: ["packages/app/src/**"]` is rejected at config-resolve time with `FALLOW-BOUNDARY-ROOT-REDUNDANT-PREFIX`, because patterns are already resolved relative to the root. Drop the root prefix from the pattern (`patterns: ["src/**"]`).
</Warning>

### Overriding preset zones

Start from a preset and customize specific zones or rules. Zones with the same name replace the preset zone; rules with the same `from` replace the preset rule.

```jsonc theme={null}
{
  "boundaries": {
    "preset": "hexagonal",
    "zones": [
      { "name": "domain", "patterns": ["src/core/**"] }
    ]
  }
}
```

This keeps `adapters` and `ports` from the hexagonal preset but replaces the `domain` zone pattern with `src/core/**`.

## Suppressing violations

Suppress individual findings with inline comments:

```typescript theme={null}
// fallow-ignore-next-line boundary-violation
import { db } from '../data/client';
```

Or suppress all boundary violations in a file:

```typescript theme={null}
// fallow-ignore-file boundary-violation
```

To suppress boundary checking entirely, set the rule severity to `off`:

```jsonc theme={null}
{
  "rules": {
    "boundary-violation": "off"
  }
}
```

<Tip>
  When introducing boundaries to an existing codebase, start with `"warn"` severity. Fix violations incrementally, then switch to `"error"` once the codebase is clean.
</Tip>

## Output formats

Boundary violations appear in all output formats:

<Tabs>
  <Tab title="Human">
    ```bash title="$ fallow dead-code --boundary-violations" theme={null}
    Boundary violations (2)

      src/features/auth/login.ts:3 → src/features/billing/api.ts (features → features)
      src/components/Button.tsx:1 → src/server/db/client.ts (shared → server)
    ```
  </Tab>

  <Tab title="JSON">
    ```json theme={null}
    {
      "boundary_violations": [
        {
          "from_path": "src/features/auth/login.ts",
          "to_path": "src/features/billing/api.ts",
          "from_zone": "features",
          "to_zone": "features",
          "import_specifier": "../billing/api",
          "line": 3,
          "col": 0
        }
      ]
    }
    ```

    <Note>
      The full JSON output includes a `schema_version`, `version`, `elapsed_ms`, and all issue type arrays. Only `boundary_violations` is shown here.
    </Note>
  </Tab>

  <Tab title="Compact">
    ```
    boundary-violation:src/features/auth/login.ts:3:src/features/auth/login.ts -> src/features/billing/api.ts (features -> features)
    ```
  </Tab>
</Tabs>

## Inspecting your boundaries

Use `fallow list --boundaries` to verify your configuration before running analysis:

```bash theme={null}
# Human-readable summary
fallow list --boundaries

# JSON for scripting or MCP tools
fallow list --boundaries --format json --quiet
```

<Note>
  Fallow warns when a zone matches zero files. This usually means the glob pattern doesn't match your directory structure. Run `fallow list --boundaries` to check file counts per zone.
</Note>

## See also

<CardGroup cols={3}>
  <Card title="fallow dead-code" icon="terminal" href="/cli/dead-code">
    CLI reference for the dead code command, including all issue type filters.
  </Card>

  <Card title="Rules & Severity" icon="scale-balanced" href="/configuration/rules">
    Set boundary violations to error, warn, or off.
  </Card>

  <Card title="Inline Suppression" icon="comment-slash" href="/configuration/suppression">
    Suppress individual findings in source code.
  </Card>
</CardGroup>
