Skip to content

DTO and DAO — Explained with Examples

DodaTech Updated Jun 15, 2026 2 min read

DTO (Data Transfer Object) carries data between layers while DAO (Data Access Object) encapsulates database operations behind an abstract interface.

DTO stands for Data Transfer Object — a simple object that carries data between processes or layers without any business logic. DAO stands for Data Access Object — an object that abstracts and encapsulates all access to a data source.

Why DTO and DAO Matter

DTOs prevent exposing internal entities to external clients (APIs, views) and reduce the number of remote calls by aggregating data. DAOs centralize data access logic, making it swappable and testable. Together, they enforce clean separation between data storage, business logic, and data presentation.

Real-World Analogy

A restaurant: the DAO is the kitchen inventory system — it knows where ingredients are stored and how to retrieve them. The DTO is the takeout container — it holds the prepared food (data) without any cooking instructions (no business logic). The customer never sees the inventory system or the kitchen.

Example: DTO and DAO

from dataclasses import dataclass
from typing import List, Optional

# DTO — just data, no behavior
@dataclass
class UserDTO:
    id: int
    name: str
    email: str
    role: str

# Internal entity — may have business logic
class User:
    def __init__(self, id, name, email, role):
        self.id = id
        self.name = name
        self.email = email
        self.role = role

    def to_dto(self) -> UserDTO:
        return UserDTO(self.id, self.name, self.email, self.role)

    @staticmethod
    def from_dto(dto: UserDTO) -> "User":
        return User(dto.id, dto.name, dto.email, dto.role)

# DAO — encapsulates data access
class UserDAO:
    def __init__(self, db_connection):
        self.db = db_connection

    def find_by_id(self, user_id: int) -> Optional[User]:
        # raw SQL or ORM call
        row = self.db.execute("SELECT * FROM users WHERE id = ?", (user_id,))
        if row:
            return User(*row)
        return None

    def save(self, user: User):
        self.db.execute(
            "INSERT INTO users (id, name, email, role) VALUES (?, ?, ?, ?)",
            (user.id, user.name, user.email, user.role)
        )

# Business layer
class UserService:
    def __init__(self, dao: UserDAO):
        self.dao = dao

    def get_user(self, user_id: int) -> Optional[UserDTO]:
        user = self.dao.find_by_id(user_id)
        return user.to_dto() if user else None

Related Terms

Repository Pattern, ORM, Clean Architecture, CRUD

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro