TL;DR: I built a Python CLI that generates enterprise NestJS (CQRS/DDD) and React backends from YAML. It's open-source on PyPI. Here is how I architected it.
You can check out the source code on GitHub or install the package directly from PyPI.
For Nest.js
maher1719
/
Nestjs-clean-architecture-crud-modules-generator
π Python CLI to auto-generate strict Clean Architecture, DDD, and CQRS modules for NestJS from YAML. Swagger & TypeORM ready.
ποΈ NestJS Clean Architecture CRUD Generator
Stop writing boilerplate. Generate production-grade, strictly-typed NestJS modules following Clean Architecture, Domain-Driven Design (DDD), and CQRS from a single YAML file.
Define your entity, run one command, and get a fully structured module with domain logic, CQRS handlers, TypeORM persistence, DTO validation, Swagger documentation, and REST controllers.
β¨ Features
| Feature | Description |
|---|---|
| ποΈ Clean Architecture | Strict domain / application / infrastructure / presentation layering. |
| β‘ CQRS | Separate Commands & Queries with dedicated Handlers. |
| π All 4 Relations |
many-to-one, one-to-many, one-to-one, many-to-many with proper FK ownership. |
| π§© Aggregates (DDD) | Parent validation, cascade enforcement, and auto-generated nested read routes. |
| π PUT vs PATCH | Strict separation between full Replace and partial Update. |
| π Production Lists | Built-in Pagination, Whitelisted Filtering, and Sorting (v3). |
| π Swagger & Validation | Auto-generated class-validator DTOs and @nestjs/swagger decorators. |
| ποΈ Module Manifest |
.generator.manifest.json tracks every generated module for easy |
Why choose Clean Architecture
Let's be honest, clean architecture is a good choice when you want to make maintainable, scalable, and predictable software. It has separation of concerns, modularity, and an onion-layered architecture so that one can extend the project's tools and infrastructure. It is just good for not spaghettifying your software and locking it into dependencies you cannot remove without breaking the whole project.
However, it comes with a verbose and tiresome setup. For each entity you make, you need to make many different folders and files with certain exact names. A CRUD-heavy app will probably need more setup time, effort, and verification of folder and file names than the actual code without clean architecture. Also, even with a complex enterprise app, we could have at least ten or more entities, each one coming with its own setup of, again, folders and files, and when you repeat that, you will discover you just most of the time need to copy, paste, and change names...
That is a major hurdle: you spent a great amount of time on setup more than needed and testing the suitability of what you did, giving complex logic and new features less and less time.
However, if we repeat and copy-paste most of the CRUD setup, why not automate it? Automating the boring and tiresome hurdle, ensuring that, with careful design of the automation, it is predictable and the same across the different entities; That will mean fewer bugs: fix one, fix for all, homogeneous, all automated, are the same; no ninja or lazy special code for just one case that is hard to debug or maintain; all team members who generate will have the same structure of code... And most of all, more time to focus on the complex, fun things.
Since I started working with clean architecture, I was impressed by how ordered and clean it is, but I was tired of repetitive setup. That's why I saw the opportunity to automate the CRUD operations with code that will generate entities, their CRUD operations, and relationships.
Building the NestJS Automation
I first made a NestJS Clean Architecture code generator that handles the creation of entities with their folders and files. then I made a template of files and, inside them, the variable that need to change (e.g entity name, entity properties...), and the content of each file, since it is the same structure for each file type; only known variables need to change. It was really a blessing.
here the template tree:
.
βββ application
βΒ Β βββ commands
βΒ Β βΒ Β βββ create-entity
βΒ Β βΒ Β βΒ Β βββ create-entity.command.ts.tpl
βΒ Β βΒ Β βΒ Β βββ create-entity.handler.ts.tpl
βΒ Β βΒ Β βββ delete-entity
βΒ Β βΒ Β βΒ Β βββ delete-entity.command.ts.tpl
βΒ Β βΒ Β βΒ Β βββ delete-entity.handler.ts.tpl
βΒ Β βΒ Β βββ replace-entity
βΒ Β βΒ Β βΒ Β βββ replace-entity.command.ts.tpl
βΒ Β βΒ Β βΒ Β βββ replace-entity.handler.ts.tpl
βΒ Β βΒ Β βββ update-entity
βΒ Β βΒ Β βββ update-entity.command.ts.tpl
βΒ Β βΒ Β βββ update-entity.handler.ts.tpl
βΒ Β βββ queries
βΒ Β βββ get-entity
βΒ Β βΒ Β βββ get-entity.handler.ts.tpl
βΒ Β βΒ Β βββ get-entity.query.ts.tpl
βΒ Β βββ list-entity
βΒ Β βββ list-entity.handler.ts.tpl
βΒ Β βββ list-entity.query.ts.tpl
βββ domain
βΒ Β βββ entities
βΒ Β βΒ Β βββ entity.entity.ts.tpl
βΒ Β βββ repositories
βΒ Β βββ entity.repository.ts.tpl
βΒ Β βββ list-options.ts.tpl
βββ infrastructure
βΒ Β βββ persistence
βΒ Β βββ mappers
βΒ Β βΒ Β βββ entity.persistence-mapper.ts.tpl
βΒ Β βββ typeorm
βΒ Β βββ entity.orm-entity.ts.tpl
βΒ Β βββ entity.typeorm-repository.ts.tpl
βββ module.ts.tpl
βββ presentation
βββ controllers
βΒ Β βββ entity.controller.ts.tpl
βΒ Β βββ nested-list.controller.ts.tpl
βββ dto
βββ create-entity.dto.ts.tpl
βββ list-entity.dto.ts.tpl
βββ replace-entity.dto.ts.tpl
βββ update-entity.dto.ts.tpl
20 directories, 25 files
That is 20 directories and 25 files generated! And also 45 times you click "new folder" or "new file" and write the name! Imagine you have at least 10 entities; it will be 450 times. If we take 30 seconds to set up a single entity for each new file or folder, we need at least 22.5 minutes; with 10 entities, that's at least 3 hours 45 minutes just for basic setup! And 20 entities will be 7.5 hours, an entire workday of non-stop, flawless creation, without even writing any code. That alone is the most tedious.
Also, for the generator to know what entities and their properties, I made it read Ya YAMLfile so we can keep track of what we will generate or update it easily. Here is an example of a comment entity:
# modules/comment.yml
module: comments
parent: posts
entity:
name: Comment
table: comments
fields:
- name: text
type: string
- name: postId
type: uuid
filterable: true
- name: authorId
type: uuid
filterable: true #For sorting
relations:
# This is the AGGREGATE parent (must be cascade + non-nullable)
- name: post
type: many-to-one
target: Post
targetModule: posts
foreignKey: postId
nullable: false
onDelete: cascade
# This is just an association (also gets a nested GET, but not the "parent")
- name: author
type: many-to-one
target: User
targetModule: users
foreignKey: authorId
nullable: false
onDelete: cascade
operations:
- create
- list
- get
- update
- delete
Here we have an example of an entity specification file: the name of the module, the parent name when it has aggregation, then the entity name and its database table name, its fields, its relationships, and its operations...
We have enough information to make CRUD modules and write the files content. Also, when we delete, what will happen to other related entities? It follows database operations.
For the generator itself, it is written in Python; here is the Python file tree
generator/
βββ structure/
β βββ cli.py # Entry point (single + bulk)
β βββ config_loader.py # YAML loading + aggregate validation
β βββ generator.py # Orchestrates file writing
β βββ context.py # Builds the template context
β βββ output_mapper.py # Template β output path mapping
β βββ manifest.py # .generator.manifest.json upsert
β βββ app_module_updater.py # Idempotent app.module.ts registration
β βββ fields/ # Field builder package
β β βββ normalization.py # normalize fields/relations
β β βββ types.py # ts_type, typeorm_type
β β βββ domain.py # entity/command/handler builders
β β βββ dto.py # DTO + validator + swagger builders
β β βββ orm.py # ORM columns + imports
β β βββ mapping.py # domain β ORM field mapping
β β βββ registry.py # build_field_context orchestrator
β βββ relations/ # Relation builders
β βββ many_to_one.py
β βββ one_to_many.py
β βββ one_to_one.py
β βββ many_to_many.py
β βββ registry.py # relation dispatcher
βββ templates/ # .tpl template sources
With that, it will handle folder and file creation and code generation, support relations, and handle pagination and sorting.
For the command to generate the modules, either specific ones or bulk generation, it will skip files that have already been generated, or you could force generation with --force:
# Generate a single module
python -m generator.structure.cli modules/comment.yml --src src/
# Bulk generate an entire folder
python -m generator.structure.cli modules/ --src src/ --force
And with that, you could have the full project CRUD generated, ready for migration and already with Swagger!
Disclaimer
While all this is good on day one, it is recommended to add any business custom logic outside the folders generated, so you can preserve your custom work!
Also, automated testing files for generated code are not yet implemented, since I prioritized building first, but everything works with manual testing.
What next?
I also made a React frontend counterpart of the generator that accords with our backend generator! I will write the next as an article!
Conclusion
Clean Architecture is very powerful, yet its setup overshadows its long-term benefits; with this generator, we could bypass its disadvantages to our advantage.
If you're a CTO or engineering manager who values strict DDD and automated developer experience, I'm currently open to remote backend/full-stack roles. The generator is open-source on PyPI β try it out, and if it saves your team hours, let's talk.
What do you think? What architecture do you use most in your project, and how do you handle the least favourite parts? Share with us in a comment so we can benefit each other!
Top comments (0)