ArchUnit 2.4.0-alpha.2
dotnet add package ArchUnit --version 2.4.0-alpha.2
NuGet\Install-Package ArchUnit -Version 2.4.0-alpha.2
<PackageReference Include="ArchUnit" Version="2.4.0-alpha.2" />
<PackageVersion Include="ArchUnit" Version="2.4.0-alpha.2" />
<PackageReference Include="ArchUnit" />
paket add ArchUnit --version 2.4.0-alpha.2
#r "nuget: ArchUnit, 2.4.0-alpha.2"
#:package ArchUnit@2.4.0-alpha.2
#addin nuget:?package=ArchUnit&version=2.4.0-alpha.2&prerelease
#tool nuget:?package=ArchUnit&version=2.4.0-alpha.2&prerelease
ArchUnit - Architecture Testing for .NET
<div align="center" name="top">
</div>
Alpha prerelease: ArchUnit for .NET is under active development. APIs and behavior may change, and the full test suite is not yet green. Use this release for evaluation only.
Enforce architecture rules in C# and .NET projects. Check dependency directions, detect circular dependencies, validate layers, measure cohesion, and generate reports. Integrates with xUnit, NUnit, MSTest, and any testing framework that can assert on returned violations.
A .NET implementation inspired by ArchUnitTS and the original ArchUnit. This project is not affiliated with TNG.
Setup • Use Cases • Features • Pattern Matching • Contributing • Documentation
⚡ 5 min Quickstart
Installation
dotnet add package ArchUnit --version 2.4.0-alpha.2
Add tests
Simply add architecture rules to your existing test suites. The following example uses xUnit. First, ensure that the project has no circular dependencies.
using ArchUnitNet;
using ArchUnitNet.Testing.XUnit;
[Fact]
public async Task ProjectShouldNotHaveCircularDependencies()
{
var rule = ArchUnit.ProjectFiles("./MyProject.csproj")
.InPath("src/**")
.Should()
.HaveNoCycles();
await rule.PassesAsync();
}
Next, ensure that the layered architecture is respected.
[Fact]
public async Task PresentationShouldNotDependOnData()
{
var rule = ArchUnit.ProjectFiles("./MyProject.csproj")
.InPath("src/Presentation/**")
.ShouldNot()
.DependOnFiles()
.InPath("src/Data/**");
await rule.PassesAsync();
}
Lastly, add a code-metric rule for a specific class.
[Fact]
public async Task OrderServiceShouldHaveHighCohesion()
{
var rule = ArchUnit.Metrics<OrderService>()
.Methods()
.LCOM96a()
.ShouldBeLessThan(0.5);
await rule.PassesAsync();
}
CI Integration
These rules are regular tests, so they run automatically in the existing test setup and CI pipeline:
dotnet test
This setup ensures that the architectural rules you define remain enforced as the codebase changes. 🌻🐣
Reports can also be saved as CI artifacts. For example, violations can be exported as SARIF, JSON, text, or HTML:
using ArchUnitNet.Reporting;
var violations = (await rule.CheckAsync()).ToList();
var report = new ViolationReportExporter(violations, "MyProject");
await report.ExportToSARIFAsync("reports/architecture.sarif");
await report.ExportToHTMLAsync("reports/architecture.html");
🚐 Setup
Installation:
dotnet add package ArchUnit --version 2.4.0-alpha.2
The package exposes framework-specific assertion adapters and a framework-agnostic fallback. Add the normal runner packages for the testing framework used by your project.
xUnit
Import the xUnit adapter and use PassesAsync():
using ArchUnitNet.Testing.XUnit;
await rule.PassesAsync();
NUnit
Import the NUnit adapter and use PassAsync():
using ArchUnitNet.Testing.NUnit;
await rule.PassAsync();
MSTest
Import the MSTest adapter and use PassAsync():
using ArchUnitNet.Testing.MSTest;
await rule.PassAsync();
Other Framework
For any other framework, inspect the returned violations or use the synchronous framework-agnostic assertion helper:
using ArchUnitNet.Testing;
ArchAssert.Passes(rule);
🐹 Use Cases
The fluent API covers common architectural fitness functions.
Layered Architecture: prevent presentation code from reaching directly into data-access code.
var rule = ArchUnit.ProjectFiles("./MyProject.csproj")
.InPath("src/Presentation/**")
.ShouldNot()
.DependOnFiles()
.InPath("src/Data/**");
Public API Protection: stop external-facing code from depending on internal implementation details.
var rule = ArchUnit.ProjectFiles("./MyProject.csproj")
.InPath("src/Public/**")
.ShouldNot()
.DependOnFiles()
.InPath("src/**/Internal/**");
Feature Isolation: keep feature folders independent with the built-in preset or explicit dependency rules.
var preset = ArchitecturePresets.FeatureIsolation()
.WithProjectPath("./MyProject.csproj")
.WithFeaturesPath("src/Features/*");
Gradual Adoption: record known violations in a baseline and fail only on new ones.
var baseline = await ViolationBaseline.LoadFromFileAsync("architecture-baseline.json");
var newViolations = violations.WithoutBaseline(baseline);
🐣 Features
This is an overview of what you can do with ArchUnit for .NET.
Circular Dependencies
var rule = ArchUnit.ProjectFiles("./MyProject.csproj")
.InFolder("src/Services")
.Should()
.HaveNoCycles();
await rule.PassesAsync();
Layer Dependencies
Use file rules for direct boundaries or define named layers with {Layer} path extraction.
using ArchUnitNet.Layers.Common;
var rule = ArchUnit.ProjectLayers("./MyProject.csproj")
.DefinedBy("src/{Layer}/**")
.Where(Layer.Defined("Presentation"))
.MayOnlyDependOn(
Layer.Defined("Business"),
Layer.Defined("Common"));
await rule.PassesAsync();
Naming Conventions
var rule = ArchUnit.ProjectFiles("./MyProject.csproj")
.InFolder("src/Services")
.Should()
.HaveName("*Service.cs");
await rule.PassesAsync();
Code Metrics
LCOM cohesion and count thresholds can target concrete .NET types.
var cohesionRule = ArchUnit.Metrics<OrderService>()
.Methods()
.LCOM96b()
.ShouldBeLessThan(0.5);
var methodCountRule = ArchUnit.Metrics<OrderService>()
.Classes()
.MethodCount()
.ShouldHaveAtMost(20);
Supported cohesion variants include LCOM1, LCOM96a, LCOM96b, and LCOM1995. Count rules cover methods, fields, and field access.
Custom Rules
Define custom file or dependency predicates when a built-in rule is not enough.
var rule = ArchUnit.ProjectFiles("./MyProject.csproj")
.InPath("src/**")
.Should()
.AdhereTo(
file => file.NonBlankLineCount < 500,
"Source files should stay below 500 non-blank lines");
await rule.PassesAsync();
Architecture Slices
Group files into logical slices and check that slice dependencies remain acyclic.
var rule = ArchUnit.ProjectSlices("./MyProject.csproj")
.DefinedBy("src/{Slice}/**")
.Should()
.BeAcyclic();
await rule.PassesAsync();
Architecture Presets
Built-in presets cover common structures:
- Layered architecture
- Hexagonal architecture
- Feature isolation
- Microservices
- Clean architecture
- Modular monoliths
- Domain-driven design
- Event-driven architecture
Presets produce regular rules that can be composed and checked like hand-written rules.
Dependency Graph Reports
Generate dependency graphs in several formats and narrow them to the code you want to inspect.
using ArchUnitNet.Common.Extraction;
using ArchUnitNet.GraphReporting;
var graph = await new DependencyExtractor()
.ExtractGraphAsync("./MyProject.csproj");
await ArchUnit.ProjectGraph()
.AddEdges(graph.Edges)
.CollapseToFolderDepth(2)
.ExportToFileAsync(
GraphExportFormat.Mermaid,
"reports/dependencies.mmd");
Supported formats:
- DOT
- Mermaid
- D2
- CSV
- JSON
- HTML
Graph exploration supports external dependencies, folder-depth collapsing, and path-focused views.
Reports
Architecture violations can be exported for people and CI systems:
- HTML for a readable report
- SARIF for GitHub and other code-scanning tools
- JSON for programmatic processing
- Text for build artifacts and logs
Metrics reports are also available in HTML and JSON. Reporting remains experimental in the alpha releases.
Configuration and Baselines
Load and save JSON rule configuration:
using ArchUnitNet.Configuration;
var configuration = await RuleConfiguration.LoadFromFileAsync("architecture-rules.json");
Use violation baselines and rule snapshots to introduce architecture checks gradually without hiding new regressions.
Performance Profiling
Profile a rule when architecture checks become part of a larger test suite:
using ArchUnitNet.Performance;
var (violations, profile) = await rule.ProfileCheckAsync("Layer boundaries");
Console.WriteLine(profile.GetFormattedExecutionTime());
🔎 Pattern Matching System
The file-rule API offers three targeting options:
InPath(pattern)checks a glob against the full normalized path.InFolder(folder)targets everything below a folder.ByName(pattern)checks a glob against file names.
Glob Patterns Guide
| Pattern | Meaning |
|---|---|
* |
Any characters except a path separator |
** |
Any number of folders and files |
? |
One character |
src/**/*.cs |
Every C# file below src |
src/Services/** |
Everything below src/Services |
**/*Service.cs |
Every file ending in Service.cs |
Pattern Matching Examples
var services = ArchUnit.ProjectFiles("./MyProject.csproj")
.InPath("src/**/*Service.cs");
var repositories = ArchUnit.ProjectFiles("./MyProject.csproj")
.InFolder("src/Repositories");
var controllers = ArchUnit.ProjectFiles("./MyProject.csproj")
.ByName("*Controller.cs");
Use forward slashes in patterns. Extracted paths are normalized before matching.
📢 Informative Error Messages
Framework adapters convert violations into native test failures. Messages contain the violated rule and the relevant source and target paths so failures can be investigated directly from test output.
You can also check rules directly when custom reporting is needed:
var violations = await rule.CheckAsync();
foreach (var violation in violations)
{
Console.WriteLine(violation);
}
Empty matches fail by default for rules that support empty-test protection. This prevents a typo in a path from silently turning an architecture test green. CheckOptions can explicitly allow empty checks where appropriate.
🏈 Architecture Fitness Functions
ArchUnit rules are executable architecture fitness functions. Because they live in normal .NET test projects, they can be reviewed with the code, run locally, and enforced in CI together with unit and integration tests.
🔲 Core Modules
| Module | Description | Alpha status |
|---|---|---|
| Files | File, folder, naming, and dependency rules | Available |
| Layers | Named layer extraction and dependency constraints | Available |
| Metrics | Cohesion and count metrics | Available |
| Slices | Logical architecture slicing | Available |
| Graph | Dependency graph reports | Experimental |
| Testing | xUnit, NUnit, MSTest, and generic assertions | Available |
| Reporting | HTML, SARIF, JSON, text, and metrics reports | Experimental |
| Common | Extraction, projections, matching, and shared types | Internal foundation |
🕵️ Technical Deep Dive
ArchUnit uses Roslyn to parse C# syntax trees from the project referenced by each rule. It turns using directives and other dependency information into a graph, projects that graph into files, layers, or slices, and evaluates fluent constraints against the result.
Project files → Roslyn extraction → Dependency graph
→ Files / Layers / Slices / Metrics
→ Violations → Test failure or report
The implementation is organized so extraction, projection, assertion, and reporting remain separate. See the architecture documentation for more detail.
🦊 Contributing
Contributions are very welcome. Please open a focused issue or pull request and keep changes covered by the relevant architecture or unit tests. See the contributing guide for repository conventions.
ℹ️ FAQ
Q: Which .NET testing frameworks are supported?
xUnit, NUnit, and MSTest have dedicated assertion adapters. Any other framework can inspect CheckAsync() results or use ArchAssert.
Q: Does the NuGet package name match the namespace?
The package is installed as ArchUnit. Existing C# namespaces remain under ArchUnitNet, for example using ArchUnitNet;.
Q: Can I use ArchUnit in CI?
Yes. Architecture checks are normal tests and run through dotnet test. Reports can be retained as pipeline artifacts.
Q: How do I adopt rules in a codebase with existing violations?
Create a ViolationBaseline, filter known violations, and fail only when new violations appear. The baseline can be reduced as the architecture improves.
Q: Is this release stable?
No. The current package is an alpha prerelease. APIs may change, and some repository tests are still failing.
📅 Plans
The immediate focus is to stabilize the public API, bring the complete test suite back to green, harden project extraction across platforms, and validate the package with realistic .NET example repositories.
🐣 Origin Story
ArchUnit for .NET brings the architecture-testing approach used by ArchUnitTS to C# projects: architecture rules should be executable, readable, and enforced continuously alongside the rest of the test suite.
💟 Community
Maintainers
- LukasNiessen - Maintainer
Contributors
See everyone who has contributed on the GitHub contributors page.
Questions
Found a bug or want to discuss a feature?
- Submit an issue on GitHub
- Join the GitHub Discussions
- Read the documentation
If ArchUnit helps your project, please consider:
- Starring the repository 💚
- Suggesting new features 💭
- Contributing code or documentation ⌨️
Star History
📄 License
This project is available under the Apache License 2.0. See the license for details.
<p align="center"> <a href="#top"><strong>Go Back to Top</strong></a> </p>
Post Scriptum
Special Note on Cycle-Free Checks
Cycle-free checks are intentionally scoped to the selected file set. A selected folder may contain files while having no internal dependency edges. When this happens, the cycle check avoids treating the absence of internal edges as proof that the folder itself did not match.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.CodeAnalysis.CSharp (>= 4.12.0)
- MSTest.TestFramework (>= 3.6.0)
- Newtonsoft.Json (>= 13.0.3)
- NUnit (>= 4.1.0)
- xunit (>= 2.6.6)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.4.0-alpha.2 | 80 | 8/17/2026 |
Alpha prerelease. See https://github.com/LukasNiessen/ArchUnitNET/releases for the changelog.