Skip to content

@studnicky/layer-import-boundary

Enforces a configurable allow-matrix of which hexagonal-architecture layers may import from which. Given an ordered layers list and the sourceRoot segment after which a layer name appears in the file path, the rule resolves each file's layer and each import's target layer, then checks the import against allowedImports (or a sensible default matrix — domain may only import domain; ports may import domain/ports; application may import domain/ports/application; adapters may import domain/ports/adapters; infrastructure may import any configured layer). Import targets are resolved both through aliasPrefixes (e.g. @domain/domain) and by walking relative specifiers against the importing file's path. Bare npm package imports and files outside the configured sourceRoot/layers tree are never flagged — the rule only governs imports between the architecture's own layers. This rule is typically wired together with domain-purity, adapter-only-import, and known-types-outside-adapters via the HexagonalSuite.create({...}) factory export, since all four share the same layers/sourceRoot configuration — but it is fully usable and configurable on its own.

Fixable: No · Options: Yes · Suggested severity: error

Options

NameTypeDefaultDescription
layersstring[](required)Ordered list of enforced layer names, e.g. ["domain", "ports", "application", "adapters", "infrastructure"].
sourceRootstring(required)Path segment(s) after which the layer name appears, e.g. "src".
aliasPrefixesobjectundefinedMap of path-alias prefixes (e.g. "@domain/") to their layer name.
allowedImportsobjectundefinedOverride of the default allow-matrix: source layer name → list of layers it may import from.

✗ Incorrect

ts
// domain (/repo/src/domain/user/User.ts) importing from application — forbidden per default matrix
import { Service } from '@application/Service';
ts
// domain (/repo/src/domain/user/User.ts) importing from adapters — forbidden per default matrix
import { Adapter } from '@adapters/FooAdapter';
ts
// relative import from domain resolving into adapters — forbidden, same resolution
// applies whether the specifier is aliased or relative
import { FooAdapter } from '../../adapters/fooAdapter';

✓ Correct

ts
// application importing from domain — allowed per default matrix
import { User } from '@domain/User';
ts
// infrastructure importing from adapters — allowed, infrastructure can import any configured layer
import { Adapter } from '@adapters/FooAdapter';
ts
// bare npm package import — never flagged regardless of source layer
import lodash from 'lodash';
ts
// domain importing from application, but an allowedImports override
// ({ domain: ['domain', 'application'] }) permits this direction — not flagged
import { Service } from '@application/Service';