4.8 Transfer Object
The Transfer Object pattern (also DTO, Data Transfer Object) uses a simple, data-only object to bundle several fields and move them across system layers (especially across the network) in a single transfer. The pain it solves is very concrete: calling getters one by one across the network causes many expensive remote round-trips.
Picture a remote Customer object whose name, email, phone, address, and level you want — if each field is a remote call, that's five network round-trips. A transfer object packs all fields into one object, carried back at once. The lab below lets you switch between "per-field getters" and "one transfer object" and see the difference in remote calls.
A pure data carrier
// Transfer Object: usually immutable, only fields (and getters)
public record CustomerTO(String name, String email,
String phone, int vipLevel) {}
class CustomerService { // business tier (possibly remote)
CustomerTO getCustomer(int id) {
// one call assembles all fields and returns them together
return new CustomerTO(...);
}
}Key traits:
- A transfer object holds no business logic — it's just a data container.
- It's usually immutable, for safe passing across layers.
- It's deliberately separate from the domain entity — domain objects can be complex, while a DTO exposes only the fields this transfer needs.
The comparator below uses a slider for field count to quantify the latency gap between "N round-trips" and "1 transfer."
DTOs in reality
The DTO is one of the most-used enterprise patterns today — nearly every system with an API relies on it:
- API request/response bodies: the JSON returned by REST/GraphQL is essentially a DTO, deliberately decoupled from database entities to avoid exposing internal structure.
- Layer boundaries: the service layer returns DTOs to the presentation layer, preventing domain-model details (and mutability) from seeping upward.
- Anti-corruption layer: DTOs let you adjust the externally exposed data shape without touching the core domain model.
Understand the transfer object and you understand why "database table structure" and "API JSON" should not — and need not — look identical.