← Back to blog

2026-06-10

Scalable Backends with Repository Pattern

Using the repository pattern to isolate data access, improve testability and keep business logic independent from persistence details.

The repository pattern gives the application a stable interface for data access. The service layer depends on an abstraction instead of depending directly on a database library.

export interface OrderRepository {
  findById(id: string): Promise<Order | null>;
  save(order: Order): Promise<void>;
}

export class CreateOrderService {
  constructor(private readonly orders: OrderRepository) {}

  async execute(input: CreateOrderInput) {
    const order = Order.create(input);
    await this.orders.save(order);
    return order;
  }
}

Benefits

  • The business layer becomes easier to test.
  • Persistence technology can change with less impact.
  • Domain logic stays away from SQL, ORM or driver-specific code.
export class PostgresOrderRepository implements OrderRepository {
  async findById(id: string) {
    const row = await db.order.findUnique({ where: { id } });
    return row ? Order.fromPersistence(row) : null;
  }

  async save(order: Order) {
    await db.order.upsert({
      where: { id: order.id },
      create: order.toPersistence(),
      update: order.toPersistence()
    });
  }
}