Spec-driven development vs TDD and BDD: how they differ
TDD writes a test, BDD an example in business language and SDD a specification for the agent. What each one does and why you do not have to choose.
Spec-driven development, TDD and BDD differ in what you write before the code and in who reads it: TDD a test that a runner executes, BDD an example in business language that a person reads, and SDD a specification that a coding agent reads. They are not three names for the same thing, and they don’t compete with each other either.
To follow the rest you only need two words. An automated test is a piece of code that checks that another piece does what you say it does, and the test runner is the program that runs them all and tells you which ones fail.
| Methodology | What you write first | Where it lives | Who reads it | You are done when |
|---|---|---|---|---|
| TDD | A test that fails | A test file next to the code, in the repository | The test runner. No person reads it top to bottom | The test passes and you have cleaned up the code without breaking it |
| BDD | An example of the behavior, written in business language | A .feature file in Gherkin, or the test names themselves | A person: product, QA, the customer. And then a library that runs it | The scenario is met and everyone understands why |
| SDD | A specification of the intent: what has to be built and under what constraints | A markdown document versioned in git, next to the code | A coding agent, and you when you review what it produced | The implementation meets the spec and the spec still describes the system |
If after reading the last row you still are not clear on what goes inside a spec, start with what spec-driven development is and come back here.
TDD and BDD: the test and the example
TDD (test-driven development) is a three-step cycle that Kent Beck codified in the late nineties within Extreme Programming: red, green, refactor. You write a test that fails because the function does not exist yet. You write the minimum code to make it pass. And only then do you clean up what you wrote, without changing the behavior.
// TDD: the test comes first, and it fails because total() does not exist yet (red)
test('an empty cart adds up to 0', () => {
const carrito = nuevoCarrito(); // the starting state
expect(total(carrito)).toBe(0); // what you expect to happen
});
// Then you write total() until it passes (green), and that is when you clean it up (refactor)
BDD was born out of that. Dan North named it behavior-driven development in 2003, working at ThoughtWorks, because when teaching TDD he kept hitting the same confusion: people did not know what to test or what it meant for a test to fail. His answer was to change the vocabulary. Where there was “test”, behavior. Where there were scattered checks inside the code, examples that a person can read without being a programmer.
That is where the Given/When/Then format comes from, and later Gherkin, the language of the .feature files that Cucumber runs. This is the same case as the test above, written so that someone from product can read it:
Feature: Shopping cart
Scenario: Empty cart
Given the cart has no products
When I check the total
Then the total is 0
What changes is the reader.
SDD: the specification the agent reads
Spec-driven development goes one step further: instead of a single case, you describe the full intent of a change before anyone writes a line. What has to be built, what constraints apply, what is explicitly out of scope and what counts as done. And the reader is no longer a runner or a colleague from product, but a coding agent: a model that reads files, writes code and runs commands on its own.
That change of reader is the whole difference. A test tells the agent that something is failing, but it never tells it what you were trying to build.
The term became popular during 2025 around these tools, and I cover the origin of the term separately. GitHub released Spec Kit in September of that year, and there are several other options with very different weights, which I compare in which spec framework to choose. Why a spec holds a project up better than a string of prompts is something I develop in the long guide to spec-driven development.
When each one pays off
TDD pays off when the logic is yours and it is delicate: calculations, business rules, anywhere a badly handled edge case is expensive in production.
With BDD the problem is no longer in the code but in the agreement. If product and development understand different things by “the user can cancel the order”, writing the example together before programming saves you two iterations.
The SDD case is a different one: we are not the ones writing the implementation. Delegating to an agent without a spec is asking it to guess, and it guesses well for a while until it stops.
Why you do not have to choose
We keep framing it as if we had to choose, and none of the three takes another’s place: each one operates at a different layer. The spec says what has to be built. The BDD example says how the system behaves seen from outside. The TDD test says whether one specific unit does its job. And domain-driven design plays on a fourth, perpendicular layer: it models the problem domain and the vocabulary shared by business and development, not the order in which you work.
The combination that is working best for us is to write a spec with an explicit acceptance criterion, what the implementation has to meet to be taken as good: this is implemented with tests first, and it is not considered finished until the whole suite passes green. There SDD directs the agent and TDD gives it the exit condition. The agent writes the test, watches it fail and then writes the code. It is the same old cycle, only someone else is typing.
If what interests you is how that agent that reads the spec works on the inside, what it decides and where it gets it wrong, that is exactly what I cover in the course on agentic patterns.
Frequently Asked Questions
Does spec-driven development replace TDD?
No. One describes what has to be built and the other checks that a specific piece works, so they live in the same repository without getting in each other’s way.
Can spec-driven development and TDD be combined?
Yes, and it is the combination that works best when the implementation is done by an agent. The spec carries the scope, the constraints and a literal line like this one:
Acceptance criterion: cover the edge cases of total() with tests
that fail before the implementation exists; not closed until the
suite passes green.
With that line the agent has a goal and a stopping condition. Without it, it decides on its own when it has finished, and its criterion and yours do not always match.
What is the difference between spec-driven development and DDD?
DDD is domain-driven design, the approach Eric Evans published in 2003, and it is about modeling the problem domain and sharing a common vocabulary between business and development. It says nothing about the order in which you write things. SDD does: it is an order of work, the spec before the code, not a way of modeling. They are used together without friction.
Is SDD going back to waterfall?
No, because they do not operate at the same level: waterfall freezes the requirements of the whole project before starting, and a spec sets the order of a single change, the size of a pull request. I take the full objection apart, with the cases where it does degenerate into waterfall, in the long guide to spec-driven development.