Greenfield and Brownfield
“Almost all the software being written, and practically all the important software, is being written to live in the context of other software that has been written.” — Michael Feathers
Greenfield is building from a clean slate with nothing downstream to protect; brownfield is working in and around an existing system whose consumers, contracts, and invariants must be respected. Naming which one you’re doing, out loud, to the agent, at the start of the task, is one of the highest-return acts of steering available.
Also known as: greenfield project, clean-slate development, brownfield project, legacy integration, in-place modernization.
Understand This First
- Brief – every brief implicitly declares whether the work is greenfield or brownfield; this article is about making that declaration explicit.
- Contract – brownfield work is bounded by existing contracts; greenfield work creates them from scratch.
- Technical Debt – greenfield starts with zero debt and accumulates from day one; brownfield is where the bill has been compounding for years.
Context
The terms come from farming and urban planning. A greenfield is unworked land, fertile and unbuilt on. A brownfield is previously developed land, often with contamination or infrastructure left over from an earlier use. Hopkins and Jenkins brought the framing to software in 2008 with Brownfield Application Development in .NET, where they observed that the industry had been talking as if “clean sheet of paper” were the normal starting point. It isn’t, and it wasn’t then either. Most developers spend more than 80% of their careers in brownfield. Only the first day of a new repository is truly greenfield.
The distinction is temporal, not stylistic. It doesn’t describe how you code. It describes what you’re starting with. Same language, same framework, same architecture: the work is still greenfield if nothing depends on it yet, and it becomes brownfield the instant a real consumer attaches.
This distinction has become load-bearing in the agentic era. It changes which patterns apply. Strangler Fig, Parallel Change, Deprecation, and Migration are brownfield patterns; they exist because consumers exist. YAGNI and KISS hit hardest in greenfield, where there’s no existing shape forcing your hand.
Problem
LLM coding agents are trained on a corpus heavily skewed toward brownfield work. Every Stack Overflow answer about a breaking change is brownfield. Every enterprise commit message mentioning “backwards compatibility” is brownfield. Every library release note is brownfield. Greenfield work, in proportion, is rare in the training distribution, and when it does appear, it often looks identical in form to the brownfield work that surrounds it.
Hand a well-trained agent a greenfield task and you’ll frequently get brownfield-flavored code back. Unasked-for API version prefixes on freshly-created endpoints. A version column on every table. “Deprecated” and “legacy” handlers for code paths that have never existed. Feature flags protecting features with no prior version. NULL-allowing columns “for backwards compatibility” in a table with zero deployed readers.
Each individual choice looks professional. Each is plausibly defensible in isolation. The aggregate is a codebase that reads like a ten-year-old system on day one: complexity paid for up front against a future that may never arrive.
The mirror failure happens too: an agent given brownfield work applies greenfield aggressiveness, renaming a function that six consumers still call, deleting a “deprecated” parameter that something in production actually depends on, normalizing a date-format handler that one partner relies on for ISO-8601 parsing. The tests pass because the downstream consumers aren’t in the test suite. The PR looks clean. Production breaks the next morning.
Forces
- Agents default to the dominant mode in their training data, which is brownfield, so they over-engineer greenfield code unless told otherwise.
- The wrong-mode output looks correct in isolation. Each added guardrail is defensible on its own; the mismatch only becomes visible in aggregate.
- The two modes call for different patterns, different discipline, and different reviewer instincts; treating them the same loses the benefit of both.
- Greenfield projects become brownfield the moment the first real consumer attaches, which means the mode is stateful and can change mid-project.
- Code review tends to wave through brownfield-flavored patterns as “safe” even when they’re unnecessary noise on a clean slate.
- A repo may contain both greenfield and brownfield modules, and without an explicit per-module convention the agent picks whichever feel dominant from the first file it opens.
Solution
Name the mode, name it early, and encode it where the agent will see it. The cheapest and highest-return steering move in 2026 is a single sentence at the top of the task, something like “This is greenfield; no deployed consumers; no backwards compatibility to preserve.” or “This is brownfield; the API has 14 external consumers we can’t update; preserve all current behavior.” Mode-naming collapses the agent’s default toward the correct stance.
Encode the project default in the instruction file. For a greenfield project, add a line to CLAUDE.md or AGENTS.md:
This project has no deployed users. Do not add backwards-compatibility code,
version fields, deprecation handlers, or legacy flags unless explicitly
instructed.
For a brownfield project:
This project has deployed consumers outside our control. All changes must
preserve existing contracts. Breaking changes require explicit approval
and a parallel-change plan.
Those two snippets are boring. They are also most of the article’s practical value. Paste one into your instruction file today and you’ll see the difference on the next task.
Watch for brownfield leakage in greenfield review. The patterns to flag: unasked-for API version prefixes, unasked-for schema version fields, unasked-for “legacy” or “deprecated” handlers, unasked-for “for backwards compatibility” comments, unasked-for NULL-allowing columns with backfill logic, unasked-for feature flags protecting a first-ever feature. Each is a signal the agent picked up brownfield energy it wasn’t supposed to have.
Watch for greenfield recklessness in brownfield review. The mirror list: renamed functions, removed parameters (even “unused” ones), normalized formats, deleted “deprecated” paths without a callgraph check. The brownfield discipline is change nothing you can’t prove is unreferenced. Don’t accept proof by “the tests still pass” if the consumers aren’t in the tests.
Match pattern to mode. In greenfield: YAGNI, KISS, Make Illegal States Unrepresentable, Spec-Driven Development. In brownfield: Strangler Fig, Parallel Change, Deprecation, Consumer-Driven Contract Testing, Feature Flag. Some patterns (tests, code review, clean abstractions) apply equally to both.
Treat migration as its own mode. A migration is brownfield work whose output is greenfield-shaped. It has its own discipline: cutover strategy, double-writes, dual-reads, a clear end date. Calling a migration “brownfield” makes it sound like you’re preserving behavior forever; calling it “greenfield” makes it sound like you can throw the old system away today. Neither is right.
How It Plays Out
Greenfield gone wrong. A developer asks an agent to scaffold a REST API for a brand-new service with no users yet. The output: /api/v1/users, a version column on every table, a schemaVersion field on every JSON payload, an ETag concurrency layer, and a header comment on the main entrypoint that reads “This module maintains backwards compatibility with legacy clients through…” Every element is defensible in isolation. All of it is completely unearned on day one of a service with zero consumers. Six weeks in, the version columns are all 1, the v1 path prefix is load-bearing in routing but useless in meaning, and the ETag layer is adding 40 ms of latency to every request without protecting anything. The stance was wrong from line 1, and each generation of the codebase has calcified the error.
Brownfield gone wrong. A developer asks an agent to “clean up the auth module” in a five-year-old service with 14 downstream consumers. The agent renames a helper, removes a “deprecated” parameter that six consumers still pass (unused, but accepted because the language is forgiving), and normalizes a date-format handler that one partner depends on for ISO-8601 parsing. The tests pass, because none of those consumers are in the test suite. The PR reads clean. Two consumers break in production by morning. The stance was wrong from the word “clean up.”
Greenfield done right. Same developer, new project, opens the task with: “Scaffold a REST API for this service. This is greenfield. No deployed consumers, no backwards compatibility, no versioning. Use the simplest routing that works; we’ll add versioning when we have a second consumer.” Output: /users, no version column, no schemaVersion, no ETag, no legacy comments. When a second consumer appears in month four, they ask for expand-contract versioning at that moment, which is the correct time for it. The code was simple when simple was right; it got complex only when complex was earned.
Put the mode on the first line of every non-trivial prompt: “greenfield task”, “brownfield task, preserve current behavior”, or “migration, cutover from X to Y.” Three words that save an editing cycle.
The stateful heuristic. The sharp practitioner test is one question: Is there a consumer that would notice if I changed this? If yes, brownfield, and change nothing you can’t prove is unreferenced. If no, greenfield, so do the simplest thing that works and add complexity only when a consumer appears. Ask it per module, not per repo. A single repository can contain both greenfield modules (the new billing feature with no users yet) and brownfield modules (the auth service 14 partners depend on). The answer changes as the project matures, so re-ask the question at milestones: the day a real user lands, the day you sign a partner, the day an SDK ships.
Consequences
Benefits. A one-sentence mode declaration is the shortest prompt change with the largest observable effect on agent output. It eliminates an entire class of unearned complexity in greenfield work, and an entire class of silent-breakage risk in brownfield work. It gives reviewers a clear filter (“this is greenfield-flavored code; should it be?”) that’s much easier to apply than reviewing each added line on its own merits. It clarifies which patterns in this Encyclopedia apply: the evolution cluster earns its keep in brownfield, the heuristic cluster earns its keep in greenfield.
Liabilities. The mode is stateful and needs re-declaring as projects age. A greenfield project left unlabeled for a year has quietly become brownfield, and the instruction file line that used to be correct (“no deployed users”) is now actively misleading. Multi-module repos need per-module mode tracking, which means more convention to maintain. And declaring a mode commits you to acting on it: telling the agent “this is brownfield” and then approving a breaking PR anyway teaches the agent (and the team) that the label doesn’t mean anything.
There is one further liability worth naming: the distinction is less clean than it sounds. Migrations are neither purely greenfield nor purely brownfield. Rewrites present as brownfield on day one and greenfield the instant the old system is retired. Internal tools can have real consumers (other engineers) whose needs matter even though the consumers are all inside the building. The mode is a useful first cut, not a complete taxonomy.
Related Patterns
- Contrasts with: Technical Debt – brownfield’s permanent companion; greenfield starts at zero debt, and every day of greenfield is a day debt can begin to accrue.
- Enables: Strangler Fig – the canonical brownfield pattern; it only makes sense once you’ve named the situation as brownfield.
- Enables: Parallel Change – the brownfield discipline for evolving a contract without breaking consumers.
- Enables: Deprecation – the brownfield lifecycle policy for retiring a feature on a real timeline.
- Enables: Evolutionary Modernization – the strategic framing for long-running brownfield work.
- Enables: Consumer-Driven Contract Testing – the brownfield verification discipline that proves you haven’t broken anyone.
- Uses: Brief – the brief is where the mode should be declared.
- Uses: Instruction File – where the project’s default mode is encoded for every future agent session.
- Uses: Context Engineering – mode declaration is one of the highest-return context moves you can make.
- Related: Contract – brownfield is where contracts rule; greenfield is where they’re drafted.
- Related: Boundary – a consumer on the other side of a boundary is what turns greenfield into brownfield.
- Related: Migration – migration is the hybrid mode; brownfield machinery in service of a greenfield-shaped outcome.
- Related: YAGNI and KISS – the greenfield defaults.
- Avoids: Vibe Coding – the greenfield-speed-without-discipline trap that naming the mode is not enough to prevent on its own.
- Related: DWIM – agents DWIM toward brownfield defaults because their training distribution is brownfield-weighted; this article names the specific DWIM failure.
Sources
Hopkins and Jenkins, Brownfield Application Development in .NET (Manning, 2008), introduced the greenfield/brownfield terminology to mainstream software development, arguing that “clean sheet” was a misleading default frame for an industry in which almost all serious work involves existing systems.
Michael Feathers’s Working Effectively with Legacy Code (2004) is the canonical treatment of brownfield discipline: seams, characterization tests, and the careful work of changing code you don’t fully understand. The epigraph line comes from the book’s preface.
The urban-planning and farming lineage of the terms is older. The software field borrowed from existing vocabulary, and the Wikipedia entries for Greenfield project and Brownfield (software development) document the canonical definitions and cross-domain use.
The specific observation that AI coding agents mishandle the mode distinction (defaulting to brownfield-flavored output on greenfield work) emerged across the 2026 agentic coding practitioner community as teams accumulated enough agent-generated code to recognize the pattern in aggregate.