Create, Read, Update, Delete (CRUD)
CRUD is the classic model for data manipulation that includes the operations Create, Read, Update and Delete. It applies to any persistent resource: typically a relational database, but also document stores, APIs, and other storage backends. The same data model is used for both reading and writing, with no architectural separation between the two. This approach is simple, easy to understand, and quick to implement.
✅ When is it appropriate
CRUD is suitable if most of the following apply:
- small to medium domain complexity
- simple or moderately complex data
- small team or less experience with complex architecture
- low volatility of business rules
- no need for tracking historical changes or auditing
In these cases, CRUD fits naturally because a single shared data model is all you need: each operation maps directly to straightforward database actions with no synchronization, projections, or translation layer in between. The result is fast development and a codebase that is easy for any new developer to understand.
❌ When is it NOT appropriate
CRUD may not be ideal if:
- the project has high complexity or many subdomains
- there is a high frequency of read operations, requiring optimization
- there is a need to scale read and write operations independently
- frequent changes in business rules or the need for auditing
- the domain requires event-driven patterns (e.g., reacting to changes across multiple services)
In such cases, CRUD becomes a bottleneck. Reads and writes cannot be optimized independently, and the simple model struggles to handle complex business rules or audit requirements.
👍 Advantages
- simple and quick to implement
- easy to understand for a new team
- low complexity for smaller projects
- direct mapping of entities to the database
- suitable for prototypes and MVPs (Minimum Viable Products)
👎 Disadvantages
- read and write operations cannot be independently optimized or scaled
- more complex auditing and change tracking
- limited flexibility for complex domains
- harder to implement an event-driven architecture
- can become hard to maintain in large systems if domain boundaries are not clearly defined
🛠️ Typical use cases
- small to medium applications with simple entities
- MVPs and prototypes
- CRUD applications (admin panels, internal systems)
- projects with low frequency of business rule changes
- standard web applications and APIs
⚠️ Common mistakes (anti-patterns)
- trying to implement CRUD for very complex domains
- ignoring optimization of read operations
- forcing CRUD in systems that need event-driven patterns
- underestimating auditing and historical data requirements
- lack of tests for complex operations
These mistakes result in a system that is hard to scale, difficult to audit, and increasingly messy as requirements grow.
💡 How to build on it wisely
Recommended approach:
- Use CRUD for small to medium projects.
- Regularly assess whether business rules are growing complex enough to justify switching to CQRS.
- As the project grows, consider CQRS or an event-driven architecture.
- Ensure auditing and logging for critical entities.
- Document operations and validations.
CRUD is the right default for the vast majority of projects. The signal to graduate to something more complex is not project size, but a specific tension in the data model: when you find yourself constantly compromising on how data is shaped because reads and writes want it structured differently, or when stakeholders need to know not just what the data is now but what it was at any point in the past, CRUD is reaching its natural limit.
Related topics
☕ If you found this page helpful, consider supporting my work by buying me a coffee.
Feedback & Sharing
Give us your thoughts on this page, or share it with others who may find it useful.
Share with your network:
Feedback
Found this helpful? Let me know what you think or suggest improvements 👉 Contact me.