Compare Java DTOs and value objects by purpose, lifecycle, validation, and equality so the two patterns are not used interchangeably.
DTOs and value objects are often confused because both can look small, immutable, and data-oriented. In Java, they serve different roles.
A DTO exists for transfer across a boundary. A value object exists to model a concept inside the domain.
That means the main question is not “do they both have fields?” The main question is “what job does this type do?”
| Aspect | DTO | Value Object |
|---|---|---|
| Main purpose | Carry data across a boundary | Model a domain concept |
| Business rules | Usually none | Often includes validation and invariants |
| Equality meaning | Useful but secondary | Central to the type |
| Typical scope | API, messaging, integration, projection | Domain model and business logic |
| Field design | Boundary-driven | Domain-driven |
1public record Money(BigDecimal amount, Currency currency) {
2 public Money {
3 if (amount.signum() < 0) {
4 throw new IllegalArgumentException("Amount must be non-negative");
5 }
6 }
7
8 public Money add(Money other) {
9 if (!currency.equals(other.currency)) {
10 throw new IllegalArgumentException("Currency mismatch");
11 }
12 return new Money(amount.add(other.amount), currency);
13 }
14}
Money is not just carrying fields. It owns invariants and meaningful behavior.
1public record InvoiceResponseDto(
2 String id,
3 String currency,
4 String amount,
5 String status
6) {}
This type exists because a response contract needs those fields in that format. It does not need domain arithmetic or currency-rule enforcement.
If a value object is treated like a DTO, the system may lose important invariants. If a DTO is treated like a value object, boundary code may inherit domain assumptions or internal structure it should not expose.
The two patterns can work together:
That is often the healthy relationship.
Records can implement either pattern. The syntax does not decide the role.
A record with validation and meaningful operations can be a value object. A record with no behavior and boundary-specific fields can be a DTO. The key is the role in the system, not the language feature used to write it.
When reviewing Java DTOs and value objects, ask:
DTO and value object can both be excellent small types. They become confusing only when the codebase stops naming their roles clearly.