On this page
Spec-Driven Development vs TDD: Which Comes First?
TDD drives design with failing unit tests; spec-driven development fixes behaviour and contracts first. They operate at different altitudes.
Quick answer
- Spec-driven development defines what the system must do before implementation, in prose and contracts that a human and an agent can both read.
- Test-driven development defines behaviour through failing tests written before the implementation, at the level of functions and units.
- They are complementary: a spec supplies the intent, and tests supply the executable check. Neither substitutes for the other.
- TDD is a design technique for the person writing the code; a spec is a communication artifact for everyone, including an AI agent that will write it.
- For AI-assisted work, start with the spec, derive acceptance tests from it, and use TDD inside the implementation where the design is uncertain.
What is the difference between spec-driven development and TDD?
Spec-driven development starts with a written description of the intended behaviour: the goal, the interfaces, the rules, the edge cases, and the acceptance criteria. Implementation follows the spec, and review checks the result against it. The spec is the source of truth and can be read by people who will not read the code.
Test-driven development starts with a failing test for the next small behaviour, then the minimum implementation to pass it, then a refactor. The test is the specification of that unit, expressed in code. TDD is a tight loop measured in minutes; spec-driven development is a planning artifact measured in hours or days.
| Question | Spec-driven development | Test-driven development |
|-----------------------------|------------------------------------|--------------------------------------|
| Unit of work | Feature or change | One behaviour at a time |
| Artifact | Prose + contracts + criteria | Executable tests |
| Reader | Humans, reviewers, AI agents | Developers, CI |
| Catches | Wrong feature, missed edge case | Wrong implementation, regressions |
| Fails when | Spec is vague or drifts from code | Tests mirror implementation details |
| Time horizon | Before and during a change | Continuous, inside the change |Why does AI-assisted work change the balance?
An AI agent will implement whatever is unambiguous. If the requirement exists only in your head, the agent fills the gap with a plausible default, and the result is code that works but solves a slightly different problem. A spec reduces that gap because it moves the ambiguity into a document you can correct before code exists.
TDD still matters, but it has a bootstrapping problem with agents: the assistant can write tests that assert the implementation it just wrote, which turns the suite into a description of the bug. Deriving acceptance tests from the spec, before implementation, keeps the tests anchored to intent rather than to generated code.
Where does each practice fit?
Use a spec at the boundaries: a new feature, an API contract, a data migration, or a change that touches several services. The spec captures decisions that are expensive to reverse and gives reviewers something to disagree with before the code is written.
Use TDD inside the implementation, especially for logic with branches, parsing, calculations, and state transitions. Those are the places where a test-first loop improves the design and where an agent’s confident first draft is most likely to be subtly wrong. For glue code and configuration, a test after the fact is usually enough.
How do you combine them without doubling the work?
Write the spec with acceptance criteria phrased as observable behaviour. Turn each criterion into one acceptance test before implementation starts. Then implement with a TDD loop at the unit level, using those acceptance tests as the outer boundary. The spec, the acceptance tests, and the unit tests form three levels of the same intent.
Keep the spec alive only as long as it is useful. Once the feature is shipped, the tests become the durable record and the spec becomes documentation or is archived. A spec that nobody updates after merge is worse than no spec, because it looks authoritative while describing a system that no longer exists.
Where this bites vibecoders
The common failure is asking an assistant to build a feature from a one-line prompt, then writing tests afterwards that confirm what it built. The tests pass and the feature is wrong. Writing five acceptance criteria first, in plain language, is usually enough to expose the ambiguity before any code is generated.
Where AI coding assistants get this wrong
- Skipping the spec and treating the prompt as the requirement.
- Letting the agent write both the implementation and the tests that define correctness.
- Writing acceptance criteria that restate the implementation instead of observable behaviour.
- Producing a long spec that nobody reviews, then implementing something else.
- Using TDD for every line of glue code and slowing the change for no benefit.
- Leaving the spec in the repository after it stops matching the system.
Checklist
- Write the goal and out-of-scope in one paragraph.
- List observable acceptance criteria before code.
- Turn each criterion into one test.
- Use a TDD loop for logic-heavy units.
- Review the diff against the spec, not only against the tests.
- Archive the spec when the tests become the source of truth.
FAQ
Can spec-driven development replace TDD?
No. A spec states intent but does not execute. Without tests, nothing verifies that the implementation matches the spec, and regressions go unnoticed. The spec improves the target; the tests prove you hit it. Teams that drop tests in favour of documents usually discover the difference in production.
Is a spec just a requirements document?
It overlaps, but a good spec is shorter and more operational: it includes interfaces, constraints, acceptance criteria, and explicit non-goals. A requirements document often describes what stakeholders want; a spec describes what will be built and how it will be verified.
How big should a spec be?
As small as it can be while removing the ambiguity that matters. For a single endpoint, half a page is often enough. For a cross-service migration, several pages with a rollout plan are justified. Length is not a virtue; a spec nobody reads has the same effect as no spec.
Does TDD work with AI coding agents?
It works when the tests come from a source the agent did not write — your spec, a bug report, or a contract. It works poorly when the agent writes tests for its own implementation, because the tests inherit the same misunderstanding. Use TDD as a design loop, not as self-certification.
Related topics
- What Is Spec-Driven Development?
- How to Write a Spec an AI Coding Agent Can Actually Follow
- Spec-Driven Development: A Worked Example
- How to Write Acceptance Criteria an AI Agent Can Verify
- What Is Test-Driven Development (TDD)?
- Spec-Driven Development Tools Compared