Element Descriptors
Elements are one of the three classification layers. An element is the architectural piece a file belongs to — usually a folder, such as components/Button/ or helpers/data/. Element descriptors define how to recognize those pieces from file paths.
The other two layers describe a file from different angles: its kind (see Files) and where its imports resolve to (see Modules). This page covers the element layer.
Defining Element Descriptors
Element descriptors are configured in the boundaries/elements setting as an array of objects. Each descriptor defines:
- What type/s of element/s it represents.
- What pattern to match against file paths.
- What values to capture from those paths.
export default [{
settings: {
"boundaries/elements": [
{ type: "helper", pattern: "helpers/*", capture: ["family"] },
{ type: "component", pattern: "components/*/*", capture: ["family", "elementName"] },
{ type: "module", pattern: "modules/*", capture: ["elementName"] }
]
}
}]
This is the running example used across the documentation. It maps to the following project structure:
src/
├── components/
│ ├── atoms/atom-a/{index.js, AtomA.js}
│ └── molecules/molecule-a/{index.js, MoleculeA.js}
├── helpers/
│ ├── data/{sort.js, parse.js}
│ └── permissions/roles.js
└── modules/
├── module-a/{index.js, ModuleA.js}
└── module-b/{index.js, ModuleB.js}
Here helpers/data and helpers/permissions are helper elements (with captured.family equal to "data" and "permissions"). Individual files inside an element are distinguished by their fileInternalPath.
Read the Selectors section to learn how to match these elements in rule policies, and Captured Values Matching to use the values you capture here.
During analysis, the plugin transforms descriptors into a runtime Element Descriptions. Read the section below for the full breakdown, and Classification for how it combines with the file and module layers.
Element Descriptor Properties
pattern (required)
Type: <string> | <array of strings>
A micromatch pattern to match against file paths. An array means OR — the first matching pattern wins.
Element patterns should match folders, not individual files. Do not include file extensions in element patterns. To classify individual files by kind, use file descriptors.
By default, the plugin matches patterns progressively from the right side of each file path. You only need to define the last part of the path you want to match, not the full path from the project root. To change this behavior, see partialMatch.
Example: Given a path src/helpers/data/parse.js, the plugin tries to match, in order:
parse.jsdata/parse.jshelpers/data/parse.js- and so on…
Once a pattern matches, the plugin assigns the corresponding element, then keeps searching at higher path levels for parent elements using the same logic until the full path has been analyzed.
{ type: "helper", pattern: "helpers/*", capture: ["family"] }
Why is partial (right-to-left) matching the default?
The default matching appends /**/* to the pattern and tests it against progressively longer path suffixes. This behaves like an implicit **/ prefix: components/* matches src/components/Button, packages/ui/src/components/Button, and any other path that ends in components/<something> — without you having to write the full prefix.
The main benefit is in captures. With pattern: "components/*", capture: ["componentName"], the captured slot maps directly to the folder you care about. No throwaway wildcard is needed for the path prefix. If you also need a value from the left side of the path (e.g. the module that contains the component), use basePattern and baseCapture for that segment.
This is the default only for backward compatibility, and it is exposed through the partialMatch option. Set partialMatch: false when the pattern must be anchored at the project root — for example to distinguish two components/ trees that live under different parent folders. Note that file descriptors always match the full path, with no equivalent option.
type (optional)
Type: <string>
The element type assigned to files matching the pattern (for example, "component"). It is stored in the element's types array.
{ type: "helper" }
Each descriptor must define at least one of type or category. Descriptors without a valid pattern and one of these are filtered out with a warning.
category (deprecated)
category in element descriptors is deprecated. Use file descriptor categories instead. It keeps working without changes; the full reference and migration table are on the Legacy Element Fields page.
capture (optional)
Type: <array of strings>
Captures named values from path fragments so you can reference them later in element selectors. Uses the micromatch capture feature under the hood.
Each captured fragment is stored under the key from the capture array at the same index.
{ type: "component", pattern: "components/*/*", capture: ["family", "elementName"] }
For a path components/atoms/atom-a/AtomA.js, this captures:
{ family: "atoms", elementName: "atom-a" }
Captured values can be used in element selectors to create more specific, dynamic policies.
Combine with partialMatch for targeted captures
Because partialMatch: true (the default) matches from the right side of the path, you only need wildcards in the segments you actually want to capture — intermediate directories are traversed automatically. For example, pattern: "components/*", capture: ["componentName"] captures the component folder name from any path ending in components/<something>, without writing a prefix wildcard.
If you also need a value from the left side of the path (for example, which module a component belongs to), add basePattern and baseCapture instead of expanding the pattern with extra wildcards:
{
type: "component",
pattern: "components/*",
basePattern: "src/modules/*",
capture: ["componentName"],
baseCapture: ["module"]
}
// For src/modules/auth/components/login-form: captures { module: "auth", componentName: "login-form" }
basePattern (optional)
Type: <string>
A micromatch pattern that the left side of the path (from the project root) must also match. Use it when pattern only covers the right side of the path but you also need to capture values from earlier path segments (see baseCapture).
The effective pattern becomes [basePattern]/**/[pattern].
basePattern (and baseCapture) are only meaningful when partialMatch: true (the default). When partialMatch: false, the full path is already expressed in pattern, so there is no separate left side to constrain.
{
type: "component",
pattern: "components/*",
basePattern: "src/modules/*",
capture: ["componentName"],
baseCapture: ["moduleName"]
}
baseCapture (optional)
Type: <array of strings>
Works like capture, but for basePattern. Both arrays' keys are available in selectors. Because it is the companion to basePattern, it is only applicable when partialMatch: true.
For a path src/modules/auth/components/login-form with the descriptor above, this captures:
{ moduleName: "auth", componentName: "login-form" }
Keep keys unique across capture and baseCapture. On a name collision, the value from capture wins.
partialMatch (optional)
Type: <boolean>. Default: true.
When true (the default), the pattern only needs to match a suffix of the file path, using right-to-left incremental accumulation: components/* matches src/components/Button, packages/ui/src/components/Button, and any other path ending in components/<something>, without writing the full prefix.
When set to false, the pattern is matched against the full file path from the project root (relative to rootPath). Unlike the deprecated mode: "full", the descriptor still uses folder semantics: the pattern is expanded with /**/* internally, and the resolved element path is the matched folder prefix, not the full file path. fileInternalPath is computed the same way as in folder mode. When partialMatch: false is set, mode has no effect.
partialMatch: true (default) | partialMatch: false | mode: "full" (deprecated) | |
|---|---|---|---|
| Pattern suffix | /**/* appended | /**/* appended | none |
| Match target | Right-to-left accumulated segments | Full file path | Full file path |
Element path | Matched folder | Matched folder prefix | Full file path |
partialMatch defaults to true for backward compatibility. It will most likely default to false in a future major version, and eventually be removed — requiring the full pattern is more intuitive and is already how file descriptors match. Prefer setting partialMatch: false and writing the full path from the project root when you can.
Use partialMatch: false when the pattern must be anchored at the project root — for example to distinguish two components/ trees that live under different parent folders. With it set, the pattern must specify the full path from the project root; relative patterns that omit the root prefix will not match.
{
type: "component",
pattern: "src/ui/components/*",
partialMatch: false,
capture: ["componentName"]
}
For a file at src/ui/components/Button/index.tsx:
- Matches because the full path satisfies
src/ui/components/*/**/*. element.pathissrc/ui/components/Button.fileInternalPathisindex.tsx.
mode (deprecated)
mode is deprecated. Element descriptors now always use folder-like matching; file classification use cases are covered by file descriptors, and full-path matching by partialMatch: false. It keeps working without changes; the full reference and migration steps are on the Legacy Element Fields page.
Element Matching Order
Element descriptors are evaluated in array order. The descriptor order determines the primary type: the first matching descriptor at a path level sets types[0].
With the default single-type behavior (boundaries/elements-single-type: true), only the first matching descriptor at a path level applies. With multi-type enabled (boundaries/elements-single-type: false), every descriptor that matches the same path level contributes a type, in descriptor order.
Best practice: Sort descriptors from most specific to least specific.
"boundaries/elements": [
// Most specific first
{ type: "react-component", pattern: "components/*/Component.tsx" },
// Less specific patterns after
{ type: "component", pattern: "components/*" }
]
Hierarchical Elements
The plugin supports elements being children of other elements. This relationship can be used in policies to restrict access based on the relationship (for example, only allow importing from child elements).
After finding the first match, the plugin keeps searching at higher path levels for parent elements.
"boundaries/elements": [
{ type: "component", pattern: "components/*", capture: ["componentName"] },
{ type: "module", pattern: "modules/*", capture: ["moduleName"] }
]
For path src/modules/auth/components/login-form/index.js:
- First matches the
componentelement (login-form). - Continues and matches the
moduleelement (auth) as its parent.
Parents are listed in element.parents, nearest first. See Element Description.
Multi-type Elements
By default, each element gets a single type. You can opt in to letting an element have multiple types at once, which is useful when the same folders belong to more than one architectural concept.
The element's matched types are exposed as the types array. The type selector matches only the first type (types[0]); the types selector matches any type in the array.
To enable multi-type matching, set boundaries/elements-single-type to false:
export default [{
settings: {
"boundaries/elements-single-type": false,
"boundaries/elements": [
{ type: "component", pattern: "shared/*" },
{ type: "shared", pattern: "shared/*" }
]
}
}]
With this configuration, a file under shared/* matches both descriptors at the same path level, so its element has types: ["component", "shared"]. The types accumulate in descriptor declaration order.
When multiple descriptors match at the same path level, their captured values are merged into a single object. On a key collision across descriptors, the last matching descriptor wins (i.e., later descriptors in the array override earlier ones). This applies to the main element and to each parent element independently.
Multi-type matching is off by default in the plugin: boundaries/elements-single-type defaults to true for backward compatibility. Set it to false to opt in. See the setting reference for the full details.
Two descriptors match "at the same path level" when they resolve to the same element path (the same matched folder). Parents accumulate types the same way.
Element Description
Based on element descriptors, the plugin resolves each file to a runtime element description — the element layer of an entity. It is accessed as from.element / to.element, used by selectors to match dependencies and by message templates to render dynamic error messages.
The other two layers have their own tables: File description (categories) and Module description (origin, source). See Classification for how the three combine into one entity.
| Property | Type | Description |
|---|---|---|
types | <array of strings | null> | All element types matched at the main path level (see multi-type), or null when the file matches no element descriptor. |
path | <string | null> | Path of the element (the matched folder or file when using legacy mode "file"). Relative to rootPath when inside it, absolute when outside, or null for unknown elements. |
fileInternalPath | <string | null> | Path of the file relative to its element path, or null for unknown elements. It varies depending on the file that was analyzed to get the element description. |
captured | <object | null> | Captured values from the matched descriptor, or null when there are none. |
parents | <array> | Ancestor elements, nearest first. Each parent has types, path, and captured (same meaning as above, but for the parent element). |
isIgnored | <boolean> | true when the file is excluded by ignore/include settings. |
isUnknown | <boolean> | true when the file matches no element descriptor. |
Read the Legacy Element Fields page for deprecated element description fields that are still available for backward compatibility.
Matching Elements using Selectors
To target an element, use the element sub-selector inside a policy's to:
// Match elements with the "helper" type
{ to: { element: { types: ["helper"] } } }
See Element Selectors for the full element selector reference.
Interaction with no-unknown-files
The no-unknown-files rule reports files that the plugin does not recognize. A file is reported only when it belongs to no known element and matches no file descriptor.
This means defining an element descriptor makes the matching files known: a file that matches any boundaries/elements pattern is no longer flagged, even if it does not match any file descriptor.
Next Steps
- Files - categorize files across elements with file descriptors.
- Modules - understand module origin for external and core imports.
- Selectors - match elements, files, and modules in your policies.
- Policies - write dependency policies that enforce your architecture.
- Settings - the full reference for
boundaries/files,boundaries/elements-single-type, and every other global setting.