Most Spring Boot projects start the same way.
You define entities, then you repeat the same scaffolding:
- repositories
- services (and often a “business service” layer)
- DTOs + mapping
- controllers
- validation and error handling conventions
- docs (OpenAPI/Swagger)
- migrations (Flyway)
- Docker bits
- tests + test data setup
None of that is hard. It’s just expensive in terms of time and focus—especially when you’re doing it for the 10th time.
That’s why I built Spring CRUD Generator: an open-source tool that generates a production-ready Spring Boot backend baseline from a single YAML/JSON spec—CRUD layers, optional Flyway migrations, optional OpenAPI/Swagger, optional GraphQL, optional Docker resources, optional caching, and optional tests/test data generation.
And I made it a Maven plugin on purpose.
This post is about why.
The goal: make the “baseline” reproducible
I wasn’t trying to generate “toy CRUD” code.
The goal was: generate a baseline you’d actually keep in a real project:
- JPA/Hibernate entities
- repositories, services, business services
- transfer objects + mappers
- REST controllers
- optional GraphQL schemas/resolvers
- optional OpenAPI/Swagger resources
- optional Flyway migrations
- optional Dockerfile + docker-compose
- optional unit tests + test data (Instancio / Podam)
- optional caching (Redis / Caffeine)
- optional optimistic locking
In other words: reduce boilerplate, keep structure consistent across projects, and leave developers with more time for domain logic.
Why Maven plugin (instead of a CLI)?
A CLI is tempting. It’s easy to ship, easy to run, and it feels flexible.
But after using generators in multiple teams/projects, the same friction always shows up:
1) “Works on my machine” is real for generators too
A CLI easily becomes something that:
- one person runs locally
- others forget to run
- CI doesn’t enforce
- output drifts
When generation becomes part of the build, you remove that entire class of problems.
With a Maven plugin, generation is a first-class build step. If you can build the project, you can generate the baseline—consistently.
2) Reproducibility requires versioning the generator itself
If your generator version isn’t pinned, you eventually get:
“Which version did you run when you generated this?”
With Maven, the generator version is just a dependency coordinate.
That gives you:
- repeatable outputs across machines/environments
- predictable upgrades (change version, review diff)
- easy CI consistency
3) It fits naturally into existing Java workflows
Spring Boot projects already live in Maven/Gradle land.
So instead of adding “yet another tool,” a Maven plugin integrates with what teams already use:
- local build
- CI pipeline
- multi-module setups
- profiles and environments
4) Generated code stays transparent and owned by the project
One of my strongest constraints was:
no runtime magic and no hidden framework layer.
The generator outputs code into your project. You can read it, modify it, debug it, and evolve it.
The plugin accelerates the start—then you keep full control.
The migration angle: why Maven is especially important
Migrations are where projects drift the fastest.
If you generate code but migrations are manual (or inconsistent), you still lose time—and you introduce risk.
That’s why the generator supports Flyway migrations based on differences between:
- the current YAML/JSON spec
- the previous generator state stored on disk
It maintains a state file:
.crud-generator/migration-state.json
This file allows the generator to detect schema changes and generate incremental migrations in common cases (like adding tables or adding/removing columns), without requiring you to hand-write SQL every time you tweak a model.
Important safety rule: table deletion is intentionally not generated.
If an entity disappears from the spec, the generator does not drop the table automatically. That’s a deliberate guardrail to reduce accidental data loss.
This is another reason Maven helps: state + migrations become part of the build + repo workflow, not “something someone ran locally.”
Spec-first: one file to describe your backend baseline
I wanted a single source of truth.
Instead of having your truth scattered across:
- entity annotations
- controller patterns
- DTO mapping rules
- documentation configuration
- migration scripts
- Docker resources
…the generator reads a spec (YAML/JSON) that describes entities, fields, relationships, constraints, and optional features.
Then it generates the baseline around that spec.
That’s the whole philosophy: make the boring parts declarative.
Why I didn’t build an IDE plugin first
IDE plugins can be great—especially for discoverability.
But they also:
- couple you to an editor ecosystem
- often lag behind build tool integration
- don’t guarantee CI reproducibility
For me, correctness and repeatability mattered more than UI convenience.
Once generation is stable in the build pipeline, IDE tooling becomes an optional layer—not the foundation.
What I wanted to optimize for
This is what “success” looks like for this generator:
✅ You start a Spring Boot project and skip repetitive scaffolding
✅ Your project structure stays consistent across teams/projects
✅ Your generator runs the same in CI as it does locally
✅ You can upgrade generator versions intentionally
✅ You keep full control over the generated code
✅ Migrations remain safe and incremental
✅ You spend time on business logic, not boilerplate
Final thought
I didn’t choose Maven because it was trendy.
I chose it because generators are only truly valuable when they are:
- reproducible
- versioned
- enforceable
- consistent across environments
A Maven plugin turns code generation from a “tool you sometimes run” into a reliable part of your engineering workflow.
If you want to try it, repo: https://github.com/mzivkovicdev/spring-crud-generator
Top comments (0)