Spring Boot CRUD Patterns
Overview
Deliver feature-aligned CRUD services that separate domain, application, presentation, and infrastructure layers while preserving Spring Boot 3.5+ conventions. This skill distills the essential workflow and defers detailed code listings to reference files for progressive disclosure.
When to Use
Implement REST endpoints for create/read/update/delete workflows backed by Spring Data JPA.
Refine feature packages following DDD-inspired architecture with aggregates, repositories, and application services.
Introduce DTO records, request validation, and controller mappings for external clients.
Diagnose CRUD regressions, repository contracts, or transaction boundaries in existing Spring Boot services.
Trigger phrases:
"implement Spring CRUD controller"
,
"refine feature-based repository"
,
"map DTOs for JPA aggregate"
,
"add pagination to REST list endpoint"
.
Instructions
Follow these steps to implement feature-aligned CRUD services:
1. Establish Feature Package Structure
Create feature// directories with domain, application, presentation, and infrastructure subpackages to maintain architectural boundaries.
2. Define Domain Model
Create entity classes with invariants enforced through factory methods (create, update). Keep domain logic framework-free without Spring annotations.
3. Declare Repository Interfaces
Define domain repository interfaces in domain/repository that describe persistence contracts without implementation details.
4. Implement Infrastructure Adapters
Create JPA entities in infrastructure/persistence that map to domain models. Implement Spring Data repositories that delegate to domain interfaces.
5. Build Application Services
Create @Service classes with @Transactional methods that orchestrate domain operations, repository access, and DTO mapping.
6. Define Request/Response DTOs
Use Java records or immutable classes for API contracts. Apply jakarta.validation annotations for input validation.
7. Expose REST Controllers
Create @RestController classes mapped to /api endpoints. Return ResponseEntity with appropriate status codes (201 for POST, 204 for DELETE).
8. Write Tests
Unit test domain logic in isolation. Use @DataJpaTest and Testcontainers for integration testing of persistence layer.
Prerequisites
Java 17+ project using Spring Boot 3.5.x (or later) with
spring-boot-starter-web
and
spring-boot-starter-data-jpa
.
Constructor injection enabled (Lombok
@RequiredArgsConstructor
or explicit constructors).
Access to a relational database (Testcontainers recommended for integration tests).
Familiarity with validation (
jakarta.validation
) and error handling (
ResponseStatusException
).
Quickstart Workflow
Establish Feature Structure
Create
feature//
directories for
domain
,
application
,
presentation
, and
infrastructure
.
Model the Aggregate
Define domain entities and value objects without Spring dependencies; capture invariants in methods such as
create
and
update
.
Expose Domain Ports
Declare repository interfaces in
domain/repository
describing persistence contracts.
Provide Infrastructure Adapter
Implement Spring Data adapters in
infrastructure/persistence
that map domain models to JPA entities and delegate to
JpaRepository
.
Implement Application Services
Create transactional use cases under
application/service
that orchestrate aggregates, repositories, and mapping logic.
Publish REST Controllers
Map DTO records under
presentation/rest
, expose endpoints with proper status codes, and wire validation annotations.
Validate with Tests
Run unit tests for domain logic and repository/service tests with Testcontainers for persistence verification.
Consult
references/examples-product-feature.md
for complete code listings that align with each step.
Implementation Patterns
Domain Layer
Define immutable aggregates with factory methods (
Product.create
) to centralize invariants.
Use value objects (
Money
,
Stock
) to enforce type safety and encapsulate validation.
Keep domain objects framework-free; avoid
@Entity
annotations in the domain package when using adapters.
Application Layer
Wrap use cases in
@Service
classes using constructor injection and
@Transactional
.
Map requests to domain operations and persist through domain repositories.
Return response DTOs or records produced by dedicated mappers to decouple domain from transport.
Infrastructure Layer
Implement adapters that translate between domain aggregates and JPA entities; prefer MapStruct or manual mappers for clarity.
Configure repositories with Spring Data interfaces (e.g.,
JpaRepository
) and custom queries for pagination or batch updates.
Externalize persistence properties (naming strategies, DDL mode) via
application.yml
; see
references/spring-official-docs.md
.
Presentation Layer
Structure controllers by feature (
ProductController
) and expose REST paths (
/api/products
).
Return
ResponseEntity
with appropriate codes:
201 Created
on POST,
200 OK
on GET/PUT/PATCH,
204 No Content
on DELETE.
Apply
@Valid
on request DTOs and handle errors with
@ControllerAdvice
or
ResponseStatusException
.
Validation and Observability
Write unit tests that assert domain invariants and repository contracts; refer to
references/examples-product-feature.md
integration test snippets.
Use
@DataJpaTest
and Testcontainers to validate persistence mapping, pagination, and batch operations.
Surface health and metrics through Spring Boot Actuator; monitor CRUD throughput and error rates.
Log key actions at
info
for lifecycle events (create, update, delete) and use structured logging for audit trails.
Examples
Input: Product Create Request
{
"name"
:
"Wireless Keyboard"
,
"description"
:
"Ergonomic wireless keyboard with backlight"
,
"price"
:
79.99
,
"stock"
:
50
}
Output: Created Product Response
{
"id"
:
"prod-123"
,
"name"
:
"Wireless Keyboard"
,
"description"
:
"Ergonomic wireless keyboard with backlight"
,
"price"
:
79.99
,
"stock"
:
50
,
"createdAt"
:
"2024-01-15T10:30:00Z"
,
"_links"
:
{
"self"
:
"/api/products/prod-123"
,
"update"
:
"/api/products/prod-123"
,
"delete"
:
"/api/products/prod-123"
}
}
Input: Product Update Request
{
"price"
:
69.99
,
"stock"
:
45
}
Output: Updated Product Response
{
"id"
:
"prod-123"
,
"name"
:
"Wireless Keyboard"
,
"description"
:
"Ergonomic wireless keyboard with backlight"
,
"price"
:
69.99
,
"stock"
:
45
,
"updatedAt"
:
"2024-01-15T11:45:00Z"
,
"_links"
:
{
"self"
:
"/api/products/prod-123"
}
}
Input: Delete Product
curl
-X
DELETE http://localhost:8080/api/products/prod-123
Output: 204 No Content
HTTP/1.1 204 No Content
Input: List Products with Pagination
curl
"http://localhost:8080/api/products?page=0&size=10&sort=name,asc"
Output: Paginated Product List
{
"content"
:
[
{
"id"
:
"prod-123"
,
"name"
:
"Wireless Keyboard"
,
"price"
:
69.99
,
"stock"
:
45
}
,
{
"id"
:
"prod-456"
,
"name"
:
"Wireless Mouse"
,
"price"
:
29.99
,
"stock"
:
100
}
]
,
"pageable"
:
{
"page"
:
0
,
"size"
:
10
,
"total"
:
2
,
"totalPages"
:
1
}
,
"_links"
:
{
"self"
:
"/api/products?page=0&size=10"
,
"next"
:
null
,
"last"
:
"/api/products?page=0&size=10"
}
}
Best Practices
Favor feature modules with clear boundaries; colocate domain, application, and presentation code per aggregate.
Keep DTOs immutable via Java records; convert domain types at the service boundary.
Guard write operations with transactions and optimistic locking where concurrency matters.
Normalize pagination defaults (page, size, sort) and document query parameters.
Capture links between commands and events where integration with messaging or auditing is required.
Constraints and Warnings
Avoid exposing JPA entities directly in controllers to prevent lazy-loading leaks and serialization issues.
Do not mix field injection with constructor injection; maintain immutability for easier testing.
Refrain from embedding business logic in controllers or repository adapters; keep it in domain/application layers.
Validate input aggressively to prevent constraint violations and produce consistent error payloads.
Ensure migrations (Liquibase/Flyway) mirror aggregate evolution before deploying schema changes.
References
HTTP method matrix, annotation catalog, DTO patterns.
Progressive examples from starter to advanced feature implementation.
Excerpts from official Spring guides and Spring Boot reference documentation.
Python generator to scaffold CRUD boilerplate from entity spec.
Usage:
python skills/spring-boot-crud-patterns/scripts/generate_crud_boilerplate.py --spec entity.json --package com.example.product --output ./generated
Templates required: place .tpl files in
skills/spring-boot-crud-patterns/references/
or pass
--templates-dir
; no fallback to built-ins. See
references/README.md
.
Usage guide:
references/generator-usage.md
Example spec:
skills/spring-boot-crud-patterns/assets/specs/product.json
Example with relationships:
skills/spring-boot-crud-patterns/assets/specs/product_with_rel.json