que-son-poco-y-dto

What Are POCOs and DTOs

  • 5 min

A POCO is a clean domain object with no infrastructure dependencies, while a DTO is an object designed to transport data between layers or processes.

When we delve into slightly more complex software architectures (N-Layer, Clean Architecture, Onion), we start seeing acronyms everywhere. Two of the most common, and often confused, are POCO and DTO.

Are they the same thing? Are they just classes with properties? Why do I need to duplicate my classes? Let’s break down what they are, where they come from, and most importantly, when it makes sense to use them.

FeaturePOCO (Entity)DTO
PurposeBusiness Logic and StateData Transport
BehaviorYes (Validations, calculations)No (Get/Set only)
PersistenceMapped to Database (ORM)Serialized (JSON/XML)
ContentAll domain dataOnly what the client needs

A POCO models what your system understands about the business. A DTO models what you need to send or receive.

What is a POCO?

The term POCO comes from Plain Old CLR Object (in the .NET world). In Java, they usually refer to POJO, Plain Old Java Object.

A POCO is a simple, pure class with no external framework dependencies.

Years ago, to use certain frameworks (like older versions of Entity Framework or Hibernate), your classes had to inherit from strange base classes like EntityObject or implement complex interfaces. That “cluttered” your code.

A POCO breaks away from that. It is an object that only cares about the data and domain logic.

Characteristics of a POCO

  1. Independence: Does not inherit from third-party classes (neither database nor UI).
  2. Domain Logic: Can contain methods, validations, and business-specific behavior.
  3. Persistence Ignorance: Does not know if it’s stored in SQL, a text file, or the cloud.

Examples

// A typical POCO (Domain Entity)
public class Usuario
{
    public int Id { get; set; }
    public string Nombre { get; set; }
    public string Email { get; set; }
    public string PasswordHash { get; set; } // Sensitive data
    public DateTime FechaNacimiento { get; set; }

    // ✅ A POCO can have business logic
    public bool EsMayorDeEdad()
    {
        return DateTime.Now.Year - FechaNacimiento.Year >= 18;
    }
}

Copied!

What is a DTO?

A DTO is a Data Transfer Object. Its definition is much stricter:

It is an object whose sole purpose is to transport data from one process to another (or from one layer to another).

Unlike a POCO, a DTO should have no behavior. No business logic, no complex calculations. They are simple data containers (“bags of properties”) with getters and setters.

// A DTO: Only data, no logic
public class UsuarioResumenDTO
{
    public string NombreCompleto { get; set; } // Perhaps concatenates Nombre + Apellidos
    public string Calle { get; set; }          // Flattened from Direccion
    // Notice there is NO Password or FechaNacimiento
}
Copied!

Why Do We Need DTOs?

You’re probably thinking: Why would I create another UsuarioDTO class if I already have the Usuario class? That’s just code duplication!

This is the number one complaint. But there are solid reasons (and security reasons) to do so.

Suppose you send your Usuario object (the POCO) directly to a REST API for the frontend to see. That object has the PasswordHash field. You’ve just sent the password (even if hashed) across the entire internet! 👏

With a DTO, you create a specific UsuarioPublicoDTO class that does not include that property.

Your database changes. Now the Usuarios table has new internal audit fields. If you use POCOs directly in your API, changing the database breaks the contract with the client.

By using a DTO, your database can change however it wants, as long as you correctly map the data to the DTO the client expects.

Sometimes, a POCO has complex relationships (Usuario.Pedido.Direccion.Calle). For a summary screen, you might only want the user’s name and street. Instead of sending a huge object graph, you create a flat DTO:

Think of a DTO as the Amazon package. The actual product (POCO) is inside the warehouse.

But what travels on the road is a cardboard box (DTO) optimized for transport, protecting the contents and carrying only the necessary label.

The Mapping Process

Of course, having two classes means that at some point we have to transfer data from one to the other. This is called Mapping.

We can do it manually,

public UsuarioDTO Convertir(Usuario u)
{
    return new UsuarioDTO
    {
        Nombre = u.Nombre,
        Email = u.Email
    };
}
Copied!

Or we can use Auto-Mapping libraries (like AutoMapper in .NET or MapStruct in Java) which do it automatically based on property names.

Modern Evolution: Records

In modern languages like C# 9+ or Java 14+, Records have emerged. They are the perfect candidate for DTOs.

A record is immutable by default and very concise to write. It perfectly defines the intention of “this is just data for transport”.

// Defining a DTO using Records in C#
public record UsuarioDTO(string Nombre, string Email);
Copied!