Skip to content

Configuration

Configuration lives in domainlint.json (or .domainlint.json) at the project root. All fields are optional — the defaults work for a standard src/features/ layout.

{
"rootDir": ".",
"srcDir": "src",
"featuresDir": "src/features",
"barrelFiles": ["index.ts"],
"extensions": [".ts", ".tsx"],
"tsconfigPath": "./tsconfig.json",
"exclude": ["**/node_modules/**", "**/dist/**", "**/.next/**"],
"includeDynamicImports": false,
"overrides": {
"global": {
"rules": {
"import-cycles": "error",
"cross-feature-imports": "error"
}
},
"features": {
"legacy-feature": {
"rules": {
"import-cycles": "off",
"cross-feature-imports": "warn"
}
}
}
}
}
FieldTypeDefaultDescription
rootDirstring"."Project root directory.
srcDirstring"src"Source directory to analyze.
featuresDirstring"src/features"Directory containing feature modules.
barrelFilesstring[]["index.ts"]Filenames treated as public API barrels.
extensionsstring[][".ts", ".tsx"]File extensions to include in analysis. Each entry must start with ..
tsconfigPathstring"./tsconfig.json"Path to tsconfig.json for path alias resolution.
excludestring[]["**/node_modules/**", "**/dist/**", "**/.next/**"]Glob patterns to exclude from analysis.
includeDynamicImportsbooleanfalseWhether to include await import() expressions in the dependency graph.
overridesobjectRule-level overrides (see below).
packageRulesPackageImportRestriction[]Cross-package import restrictions for monorepos (see Workspaces).
packageRulesFilestringPath to a file exporting custom workspace rules.

Overrides let you change the severity of each rule — or disable it entirely — at the global or per-feature level.

Rule nameDefaultMaps to
import-cycles"error"R1 — No import cycles
cross-feature-imports"error"R2 — Cross-feature barrel imports
no-external-feature-imports"off"Feature files cannot import from outside the features directory
LevelBehavior
"error"Reported as an error. Causes exit code 1.
"warn"Reported as a warning. Does not cause exit code 1.
"off"Rule is skipped entirely for the scope.
  1. Feature-leveloverrides.features["<featureName>"].rules applies to files inside that feature.
  2. Globaloverrides.global.rules applies to all other files.
  3. Default"error" if no override matches ("off" for no-external-feature-imports).
{
"overrides": {
"features": {
"legacy-billing": {
"rules": {
"import-cycles": "off"
}
}
}
}
}

The configuration file is validated at load time using Zod. Here is the schema used internally:

const ruleOverrideSchema = z.object({
rules: z
.object({
"import-cycles": z.enum(["off", "warn", "error"]).optional(),
"cross-feature-imports": z.enum(["off", "warn", "error"]).optional(),
"no-external-feature-imports": z.enum(["off", "warn", "error"]).optional(),
})
.optional(),
});
const configFileSchema = z.object({
rootDir: z.string().optional(),
srcDir: z.string().optional(),
featuresDir: z.string().optional(),
barrelFiles: z
.array(z.string().min(1))
.optional(),
extensions: z
.array(z.string().startsWith("."))
.optional(),
tsconfigPath: z.string().optional(),
exclude: z.array(z.string()).optional(),
includeDynamicImports: z.boolean().optional(),
overrides: z
.object({
global: ruleOverrideSchema.optional(),
features: z.record(z.string(), ruleOverrideSchema).optional(),
})
.optional(),
});

Invalid configuration will cause domainlint to exit with code 2.