Architecture Drift Detection: Keep Your Code Aligned with Design
Somewhere in your organization, there's an architecture diagram that's wrong. Maybe it shows a microservice that was merged into another six months ago. Maybe it lists Redis as the caching layer when the team switched to Memcached during a production incident. Maybe it describes a clean hexagonal architecture in a service that's accumulated enough shortcuts and workarounds to look like spaghetti.
This is architecture drift: the gradual, silent divergence between how your system is documented and how it actually works. Unlike bugs, drift doesn't trigger alerts. Unlike performance regressions, it doesn't show up in monitoring. It sits quietly until someone makes a decision based on outdated documentation -- and that decision turns out to be wrong.
Architecture drift is universal. Every team experiences it. The question isn't whether your documentation will drift, but how quickly you'll detect it and what you'll do about it.
There is no shortage of advice about the second half of that. Keep the docs next to the code. Review them in the same pull request. Make them part of the definition of done. It's good advice, most of it appears further down this page, and it shares one blind spot: it tells you what to do, not whether it worked. The closest thing to a check in the common guidance is a last-edited timestamp, which tells you when somebody touched the file rather than whether the file is true.
Detecting drift is the half that gets skipped. This guide covers the problem, the five families of detection method, and what each one can and cannot see. Two companion posts each go deeper on one thing: how a drift score is computed and what the number means, and the practices that keep a model true once you have one.
What is Architecture Drift?
Architecture drift occurs when the actual implementation of a software system diverges from its documented or intended architecture. Perry and Wolf named the problem in Foundations for the Study of Software Architecture (ACM SIGSOFT Software Engineering Notes, 1992), where they separated erosion, which comes from violating the architecture, from drift, which comes from insensitivity to it. Everyday usage has shifted since: most engineers today say "drift" for any gap between the documentation and the code, and that is the sense this guide uses. The distinction is worth keeping, and there's a section on it below.
Drift manifests at every level of architectural documentation:
Structural Drift
The documented structure no longer matches the codebase:
- A service documented as a standalone container was absorbed into a monolith
- A component was renamed but the diagram still shows the old name
- A new service was created but never added to the architecture model
- A database was migrated from MySQL to PostgreSQL but the container diagram still says MySQL
Behavioral Drift
The documented behavior no longer matches reality:
- A synchronous API call was replaced with an async message, but the relationship still says "REST/HTTP"
- A data flow was changed to go through an API gateway, but the diagram shows direct service-to-service communication
- An authentication step was added that isn't reflected in the system context diagram
Dependency Drift
The documented dependencies no longer match actual integrations:
- A third-party API was replaced with something built in-house
- A new external dependency was added (payment provider, monitoring service) but not documented
- An integration was decommissioned but still appears in the system context diagram
Decision Drift
The documented architectural decisions are no longer being followed:
- An ADR says "use PostgreSQL for all persistent storage" but a team started using MongoDB
- The conformance rules say "no direct database access from the frontend" but someone added a client-side Supabase integration
- The deployment architecture says "single region" but services were deployed to multiple regions
Why Architecture Drift Happens
Understanding the causes of drift is essential to preventing it. Drift isn't usually malicious or even negligent -- it's a natural consequence of how software is developed.
Speed Over Documentation
When shipping a feature by Friday, updating the architecture diagram is the first thing that gets dropped. The code change is the deliverable. The documentation update is overhead. This is rational behavior in the short term and devastating in the long term.
Many Small Changes
Drift rarely happens in one dramatic moment. It accumulates through hundreds of small changes, each too minor to warrant a documentation update:
- Renaming a file
- Adding a utility package
- Switching a library dependency
- Extracting a function into a separate module
No single change is significant enough to trigger a documentation update. Together, they transform the architecture.
Team Turnover
When engineers leave, they take implicit knowledge with them. The new team inherits the codebase but not the understanding of why it's structured the way it is. They make changes based on what they see in the code, not what the documentation says, widening the drift.
Lack of Feedback Loops
If nobody checks whether documentation matches reality, drift is invisible. Without a detection mechanism, the only way to discover drift is during an incident, an audit, or when a new engineer points out that the diagram doesn't match the code. By then, the drift may be extensive.
Emergency Changes
Production incidents often require architectural shortcuts: a direct database connection instead of going through the API layer, a hardcoded configuration instead of using the config service, a temporary cache that becomes permanent. These changes bypass normal review processes and are rarely documented.
The Cost of Architecture Drift
Drift isn't just an aesthetic problem. It has concrete, measurable costs.
Bad Decisions
When architects make decisions based on outdated documentation, those decisions can be wrong. "This service has low traffic, so we can afford a synchronous dependency" -- except the documentation is stale and the service actually handles 10x the documented load.
Slow Onboarding
New engineers rely on architecture documentation to build their mental model. If the documentation is wrong, they build wrong mental models. They write code that doesn't fit the actual architecture. They ask questions that reveal their confusion, consuming senior engineers' time.
Incident Response
During a production incident, architecture diagrams should help teams understand blast radius and dependencies. If those diagrams are wrong, teams waste precious minutes tracing the wrong dependency chains or missing critical upstream systems.
Compliance and Audit Failures
In regulated industries, architecture documentation is often required for compliance (SOC 2, ISO 27001, HIPAA). If auditors find that documentation doesn't match reality, it's a finding -- potentially a serious one.
AI Agent Confusion
As AI coding agents become more prevalent, they increasingly rely on architecture documentation for context. An agent that reads a stale C4 model will generate code that fits the documented architecture, not the actual one. This amplifies drift rather than fixing it.
How to Detect Architecture Drift
There are five approaches in common use, and they answer different questions. Manual review asks whether the diagram still looks right to the people in the room. Fitness functions and static analysis ask whether specific rules are being broken. LLM evaluation asks whether the code reads like the design it claims to implement. Drift scoring asks how much of the documented model still exists. Pick by which question is costing you.
Manual Review (Traditional Approach)
The simplest approach is periodic manual review: gather the team, walk through the architecture diagrams, and check whether they still match reality.
When this works: Small teams, simple architectures, quarterly cadence.
When this fails: Large systems, fast-moving teams, or when the people who know the code best don't have time for review meetings. Manual review also suffers from confirmation bias -- people tend to see what they expect to see.
Architecture Fitness Functions
Fitness functions, popularized by Neal Ford and the "Building Evolutionary Architectures" book, are automated tests that validate architectural properties:
// Example: Ensure no direct database imports in handler packages
func TestNoDatabaseImportsInHandlers(t *testing.T) {
packages := analyzeImports("./internal/handler/...")
for _, pkg := range packages {
for _, imp := range pkg.Imports {
assert.NotContains(t, imp, "database/sql",
"Handler %s imports database/sql directly", pkg.Name)
assert.NotContains(t, imp, "gorm.io",
"Handler %s imports GORM directly", pkg.Name)
}
}
}
Fitness functions are powerful for enforcing specific rules, but they require upfront effort to write and maintain. They check constraints, not the full model.
Static Analysis Tools
Tools like ArchUnit (Java), Deptrac (PHP), and go-arch-lint (Go) analyze code structure and enforce dependency rules:
// go-arch-lint configuration
components:
handler:
in: ./internal/handler/
service:
in: ./internal/service/
repository:
in: ./internal/repository/
rules:
handler:
can_depend_on: [service]
service:
can_depend_on: [repository]
repository:
can_depend_on: []
These tools are excellent for enforcing layered architecture within a single codebase. They don't address cross-service drift or validate that the architecture model matches the code.
LLM-Assisted Evaluation
Thoughtworks put architecture drift reduction with LLMs in the Assess ring of Technology Radar Vol. 34 (April 2026). Their framing of the problem is worth quoting, because it comes from somewhere other than a vendor:
Increased use of AI coding agents can accelerate drift from the intended codebase and architecture designs. Left unchecked, this drift compounds as agents and humans replicate existing patterns, including degraded ones, creating a feedback loop where poor code begets poorer code.
The technique they describe pairs deterministic analysis tools (they name Spectral, ArchUnit and Spring Modulith) with LLM evaluation, to catch semantic violations that a rule engine can't express, and then uses the LLM to help fix what it found. Their teams have applied it to API quality guidelines and to defining architectural zones that guide agent-generated changes.
Two of their lessons are worth carrying over whatever tool you use. A first scan surfaces more violations than anyone will triage, so prioritization is the real work. And an agent's fix needs its own verification loop, because "it changed the code" and "it improved the system" are different claims.
Assess is Thoughtworks' "worth looking at, we don't yet recommend it" ring. Treat it that way. What it settles is that the problem is real enough for a large consultancy to write down, which is more than most drift arguments can point at.
Automated Drift Scoring
This is the approach Archyl takes. Instead of checking specific rules, it validates the entire architecture model against the codebase:
- Does each documented system match a repository?
- Does each documented container match a directory in the codebase?
- Does each documented code element reference a file that still exists?
- Are both endpoints of each documented relationship still valid?
The result is a score from 0 to 100 and a per-element breakdown of what matched, what is documented but gone, and what exists in the code but was never written down. Where fitness functions check constraints you thought to write, this checks the whole model you already have.
The key design decisions in Archyl's drift detection:
Lightweight. No AI call and no file contents fetched. One recursive tree request to your Git provider, then path and name matching against the model. Computation takes seconds.
Deterministic. Same codebase, same model, same score. No variability from LLM temperature or prompt engineering.
Cheap. Run it on every push without cost concerns. A hundred computations a day is fine.
Actionable. The breakdown names which elements drifted, so you know what to fix.
The trade-off is in the first bullet. Checking paths and names instead of reading code makes the score fast, free and reproducible, and it means the check is structural. It sees a container whose directory is gone and a code element whose file was deleted. It does not see the REST call that became a queue message while both services kept their names. That is behavioral drift, the one kind in the taxonomy at the top of this guide that no cheap check catches. Manual review and LLM evaluation are what you have for it.
How the drift score is computed, in detail covers the formula, what is excluded from the denominator and why, and the rest of the limits.
Closing the Loop
Detection on its own changes nothing. A score somebody computes once and looks at is an audit, not a feedback loop. Three mechanisms turn it into one, plus one distinction worth getting right before you wire any of them up. The workflow practices that sit alongside them, architecture as code, documentation in the definition of done, adopting conformance rules, are the subject of living architecture documentation.
Automate Drift Detection in CI
The mechanism with the most teeth is a CI gate that fails when drift exceeds a threshold, because it is the only one that stops a merge:
on:
push:
branches: [main]
jobs:
drift:
runs-on: ubuntu-latest
steps:
- uses: archyl-com/actions/drift-score@v1
with:
api-key: ${{ secrets.ARCHYL_API_KEY }}
organization-id: ${{ secrets.ARCHYL_ORG_ID }}
project-id: 'your-project-uuid'
threshold: '70'
When the build fails because the drift score dropped, someone has to fix it before merging. Documentation accuracy becomes as non-negotiable as passing tests.
Set the threshold below your current score, not at the number you wish you had. A gate that fails on the first run gets disabled on the first run. Raise it as the team builds the habit.
Set Up Drift Alerts
Archyl supports webhook alerts for drift events:
drift.score_computed: Fires on every drift computation. Post to a Slack channel for visibility.drift.score_degraded: Fires when the score drops by 10+ points. This is your early warning system.
Configure these alerts to a channel your team monitors. Awareness is the first step toward action.
Run Architecture Reviews
Monthly or quarterly architecture reviews serve multiple purposes:
- Validate that the documented architecture still matches reality
- Identify drift that automated tools missed (behavioral drift, for example)
- Discuss whether drifted components should be updated in code or in documentation
- Review and update ADRs for decisions that may need revisiting
Don't Confuse Drift With Conformance
These get run together often enough to be worth separating, because they are computed differently and they fail for different reasons.
Drift detection asks whether your model matches reality. It compares the documented architecture against the repository and produces a score.
Conformance rules ask whether reality follows your rules: the frontend container must not depend on the database container, every public API goes through the gateway, each service owns its own database. A conformance check can pass on a model that has drifted badly, and a perfectly accurate model can violate every rule you have.
You want both, and you should not read one number as if it were the other.
Architecture Drift vs. Architecture Erosion
These terms are related but distinct:
Architecture drift is divergence between documentation and implementation. The code might be perfectly fine -- the documentation is just wrong.
Architecture erosion is degradation of the architecture itself. The code violates architectural principles, accumulates tech debt, and becomes harder to maintain. Erosion is a code quality problem. Drift is a documentation accuracy problem.
Perry and Wolf drew the line in a different place in 1992: for them both were properties of the system rather than of the documentation, with erosion caused by violating the architecture and drift caused by being insensitive to it. The modern usage is looser and more useful to a working team, but if you read the academic literature on architecture erosion, expect the terms to sit differently than they do here.
They often co-occur. When documentation drifts, teams lose awareness of the intended architecture. Without that awareness, they make changes that erode the architecture. Drift enables erosion.
This is why drift detection matters beyond just documentation accuracy. Accurate documentation serves as a reference that prevents erosion. When everyone can see the intended architecture, they're more likely to maintain it.
Measuring and Tracking Drift Over Time
A single drift score is useful. A trend is powerful.
Establish a Baseline
Run the first computation before you change anything about how the team works. Whatever it returns is your baseline, and a low first number is information rather than a verdict. Documentation that nobody has been asked to maintain has not been failing; it has been unmeasured.
Resist the urge to fix things before the first run. You want the number that describes the situation you are actually in, not the one you get after a cleanup weekend.
Track the Trend
A single score is a fact about today. The trend is what tells you whether anything you changed worked:
- Is drift getting better or worse over time?
- Did a specific sprint or release cause a drop?
- Is the CI threshold holding the line, or is everyone lowering it?
Archyl stores every computation with its full breakdown, so a historical report can be reopened and compared element by element. Whatever tool you use, keep the history. A drift score you recompute from scratch each quarter and then discard is an audit again.
Set a Target You Can Actually Hold
Pick the next number rather than the ideal one. If today is 58, the useful target is 65 and the useful conversation is about which five elements get you there. A team that agrees to reach 90% by the end of the quarter usually agrees to nothing.
The Role of Drift Detection in AI-Assisted Development
This is the part that changed most recently, and it is why Thoughtworks wrote the entry quoted earlier: agents replicate the patterns they find, degraded ones included, so drift that used to accumulate at the speed of human commits now accumulates at the speed of generated ones.
AI agents increasingly rely on architecture documentation for context. Through protocols like MCP, agents can read your C4 model, ADRs, and conformance rules before generating code. This makes them more effective -- they generate code that fits your architecture instead of guessing.
But this only works if the documentation is accurate. An agent that reads a stale C4 model and generates code based on it will produce code that fits the wrong architecture. The agent amplifies drift instead of preventing it.
Drift detection creates the feedback loop that keeps AI agents honest:
- Agent reads architecture via MCP
- Agent generates code that fits the documented architecture
- Code is merged, potentially changing the actual architecture
- Drift detection runs and catches any divergence
- CI gate fails if drift exceeds threshold
- Team updates documentation to reflect reality
- Agent reads updated architecture -- loop closes
Without step 4, the loop is open. Documentation becomes increasingly fictional. Agents increasingly generate code that fits a fantasy architecture. The gap widens with every commit.
Drift detection is the mechanism that closes this loop.
Getting Started With Drift Detection
If You Already Have a Model Somewhere
Measure it before you change anything else. This is the cheapest first move available and it commits you to nothing.
If your architecture already lives in Structurizr DSL, LikeC4, IcePanel or a Backstage catalog, bring that model across and compute a score against it as it stands. You are measuring the documentation you already wrote, in the state you already left it. No workflow change, no new habit for the team, no decision about tooling yet. The number is the input to that decision, not the result of it.
Two honest caveats. The importers are not lossless: views, styles and layout do not survive, and deployment environments and nodes are skipped, though the parser names them in its warning list with their line number, so read that list and the imported model before you trust the denominator. And the score describes the model that arrived, not the file you exported.
What comes back is a per-element list. A score of 84 is a maintenance problem you can schedule. A score of 41 means decisions have been getting made against a document that describes a different system, and it is better to learn that now than during the next incident.
If You Have No Architecture Documentation
Start with AI discovery. Connect a repository, let discovery propose the C4 model, and approve or reject what it suggests rather than drawing it. Once there's a model, drift detection is what keeps it honest.
If You're Already Tracking Drift
Put it in CI. Set a threshold below your current score. Configure the degradation alert. Make drift a metric the team sees weekly, not a number one person computes before a review.
Regardless of Where You Start
Drift compounds like tech debt: the longer you leave it, the more of it there is to reconcile, and the less anyone trusts the document in the meantime. The difference is that you can find out where you stand today without fixing anything first.
Your architecture documentation either reflects reality or it doesn't. The point of a drift score is that you no longer have to guess which.
Go deeper: how the drift score is computed for the mechanism, living architecture documentation for the practices that keep a model true, and what is the C4 model if you're starting from scratch. Definitions: architecture drift, living documentation, and drift detection in the product. The Developer plan is free and takes no card, if you want to put a number on the documentation you already have: archyl.com.