← All insights

Every Greenfield Project Becomes Brownfield. The Question Is When.

Portia Canlas, FDE10 min readEngineering

There is a moment in every software project when the team stops calling it greenfield.

It is rarely a dramatic moment. Nobody announces it. The project does not change its name. But at some point the codebase stops being a blank canvas where every decision is deliberate and starts being a system where every change has to account for what is already there. The integration boundaries multiply. The test suite slows down. New team members need onboarding time to understand the existing code before they can contribute to it.

That transition happens faster than most teams expect. For some projects it takes a year. For others it takes three sprints.

Understanding why it happens — and what accelerates it — is the difference between a codebase that ages well and one that becomes a burden before the product has even found its market.

What makes a project greenfield

Greenfield is not just about age. A two-year-old codebase with comprehensive test coverage, current documentation, and a well-understood architecture is easier to work in than a six-month-old codebase with no tests, a stale spec, and three undocumented integration boundaries added under deadline pressure.

What makes a project feel greenfield is confidence. The team knows what the system does. The tests describe it accurately. The architecture reflects the current reality. Changes can be made with a reasonable expectation of understanding their consequences.

What makes a project brownfield is uncertainty. Nobody is quite sure what that module does. The test coverage number looks good, but the tests were written to make the coverage tool happy rather than to catch real regressions. The integration boundary added in sprint four is not in the architecture document, and the developer who added it left two months ago.

Greenfield and brownfield are not descriptions of age. They are descriptions of how well the team understands the system it is building.

The three sprints that matter most

Most projects do not deteriorate gradually and uniformly. They deteriorate in specific sprints, where specific shortcuts were taken under specific pressures. Looking back at a struggling codebase, the inflection points are almost always traceable to a small number of decisions made early in the project, when the pressure to ship was highest and the structural consequences were least visible.

The deadline sprint

Every project has one. A demo is coming. A client commitment was made. A competitor is about to launch something similar. The team needs to ship something real in the next two weeks, and there is more work than time.

In the deadline sprint, tests get written to pass rather than to verify. Integration boundaries get added without being documented. The architecture takes its first shortcut that everyone agrees will be fixed in a future sprint. The system design document falls a full sprint behind the implementation for the first time.

None of this is catastrophic in isolation. Every engineering team makes these tradeoffs. The problem is that the future sprint to fix it rarely arrives. The shortcut that was meant to be temporary becomes permanent. The tests that were written to pass rather than to verify accumulate into a suite that gives false confidence. The undocumented boundary becomes the foundation that later boundaries are built on.

The integration sprint

At some point in the early life of a project, the system has to connect to something real. A third-party API. A legacy system that was not in the original plan. A mobile client with different expectations from the web client. A message queue added to solve a performance problem.

Integration work is exploratory in a way that feature work is not. The contract with the external system is discovered during implementation rather than defined before it. Mocks get written to reflect what the external system actually returned in testing, not what the specification said it should return. When the external system changes, the mock does not.

The integration sprint tends to produce the first class of undocumented behaviour in a greenfield project. The team understands it because they just built it. Six months later, when the person who built it has moved to a different project, the understanding lives in nobody's head and nowhere in the documentation.

The refactoring sprint

The architecture that made sense in sprint one does not always make sense in sprint six. Something about the domain turned out to be more complex than the initial design assumed. A naming convention that seemed clear early on has been applied inconsistently across a dozen new modules. A shared utility that was only used in two places is now used in twenty and needs to be rethought.

Refactoring sprints are healthy. The problem is when they happen faster than the test suite can follow. A refactored module whose tests were not updated to reflect the new design ends up with tests that pass for the wrong reasons. The tests describe the old structure. The code has the new structure. They happen to agree on the surface behaviour but would not catch a regression that breaks the new design's assumptions.

This is the sprint where the test suite most commonly turns from an asset into a liability. Coverage numbers stay the same or improve. The quality of what the tests actually verify quietly decreases.

Why it feels sudden

The transition from greenfield to brownfield rarely feels gradual from the inside. Teams typically experience it as a step change, at the moment when the accumulated drift becomes visible. A new team member joins and cannot find the information they need to understand the system. A change that should take two days takes two weeks because of undiscovered dependencies. A production incident reveals an integration boundary nobody knew was undocumented.

It feels sudden because the deterioration was gradual, but the consequences arrive as threshold events. A codebase can accumulate a lot of technical debt before any individual symptom crosses the line that makes it visible. Then several things cross that line at once, and it feels like the codebase went from healthy to struggling overnight.

It did not. The decisions that produced the deterioration were made in specific moments under specific pressures. They just did not become visible until later.

Two lines over time: what the dashboard shows, staying flat and green, and what the team actually understands about the system, quietly declining through the deadline, integration, and refactoring sprints until the gap crosses a threshold and becomes impossible to ignore.

The metrics that do not warn you

The standard quality metrics tend to look healthy while the transition is happening. Code coverage stays high or improves, because tests are still being written — even if they are written against the implementation rather than the requirements. The CI pipeline stays green because the tests continue to pass the code they were written to test. Static analysis complexity scores may even improve as the refactoring sprint cleans up early code.

The metrics that would warn you are the ones most teams do not track. How many integration boundaries are undocumented? How many tests assert specific expected values rather than just that something ran? How many requirements from the original specification have no corresponding test that would fail if the requirement were violated? How many modules behave in ways that contradict their stated contract?

These questions are harder to answer than a coverage percentage. They require reading the codebase against its own stated intentions, rather than just measuring what runs during a test suite execution. But they are the questions that separate a codebase that is aging well from one that is quietly accumulating invisible debt.

The characteristics of a codebase that ages well

Some codebases stay greenfield longer than others. The difference is usually not talent or discipline. It is a small number of practices that make the cost of staying current lower than the cost of falling behind.

Integration boundaries are treated as contracts, not as implementation details. Every time a boundary is added, it is documented and tested at the contract level before the feature is merged. This takes ten minutes. Discovering an undocumented boundary six months later, and understanding what it does, takes days. The investment is front-loaded and small. The cost of skipping it is back-loaded and large.

Tests are written against requirements, not just against code. A test suite that only verifies what the code does cannot detect when the code stops doing what the business requires. Adding requirement-level tests — tests that would fail if a stated business rule were violated, regardless of what the implementation looks like — gives the codebase a way to resist drift automatically. These tests are harder to write than implementation tests, because they require understanding the requirements well enough to express them as assertions. They are also the most valuable tests in the suite.

The architecture document is a living thing, not a deliverable. The most useful architecture documents are not the ones produced at the start of a project. They are the ones updated when the architecture changes. A one-page diagram that accurately reflects the current integration boundaries is worth more than a fifty-page design document last touched in month two. The question to ask at every sprint review is not "is the document complete" but "does the document reflect what we built this sprint."

New team members are a quality signal. The experience of a developer joining the project for the first time is one of the most accurate measures of how well the codebase has aged. If they can navigate the system using the existing documentation and tests within a week, the codebase is aging well. If they spend their first two weeks asking questions that cannot be answered from any written source, the brownfield transition has already happened and the team has not noticed yet.

The value of knowing where you are

The most useful thing a team can do at the end of the first few sprints is to honestly assess whether it is still working in a greenfield codebase, or whether brownfield characteristics have already begun to accumulate.

This is not a judgment about the quality of the team. It is a calibration. A team that knows it is in the early stages of a brownfield transition can make deliberate decisions about where to invest. It can prioritise documenting the undocumented boundaries before they multiply. It can strengthen the tests that were written to pass rather than to verify, before there are too many of them to fix efficiently. It can establish the practices that slow the transition, before the transition has progressed too far for practices to help.

A team that believes it is still working in a greenfield codebase, when it is not, will keep making the decisions that accelerate the transition. The shortcuts compound. The undocumented boundaries multiply. The test suite grows in coverage and shrinks in reliability. The moment the deterioration becomes visible arrives sooner than it needed to.

The greenfield-to-brownfield transition is not a failure. It is inevitable — every successful project gets harder to change as it matures. The teams that manage it best are the ones who see it coming, understand what is driving it, and invest in the right places before the cost of not investing becomes visible in production.


This article draws on patterns seen across ToolTwist's brownfield engineering engagements — the sprints where the drift starts, and the practices that keep it from compounding.