# 10 Database Design Patterns Every Senior Engineer Should Know

Most software engineers learn SQL.

Senior engineers learn **database design**.

The difference?

A junior engineer asks:

> *"Which database should we use?"*

A senior engineer asks:

> *"How should data evolve, scale, and survive the next five years?"*

The database is often the biggest bottleneck—or the biggest competitive advantage—of a system. Great schema design reduces technical debt, improves scalability, and makes future features dramatically easier to build.

Here are **10 database design patterns** every senior engineer should understand.

* * *

## 1\. Normalization

**Purpose:** Eliminate redundancy and maintain data consistency.

Instead of storing duplicate information, split data into logical tables connected by keys.

Example:

*   Users
    
*   Orders
    
*   Products
    
*   OrderItems
    

rather than placing everything into one giant table.

### Best for

*   Financial systems
    
*   ERP
    
*   CRM
    
*   Banking
    
*   Enterprise applications
    

### Benefits

*   Consistent data
    
*   Smaller storage footprint
    
*   Easier updates
    

### Trade-off

Too much normalization increases JOIN complexity.

* * *

## 2\. Denormalization

Sometimes duplication is intentional.

Modern applications often duplicate data to improve read performance.

Example:

Instead of joining five tables for every request:

```plaintext
Order
Customer
Address
Country
Currency
```

Store customer name and shipping address directly inside the Order record.

Yes, it creates redundancy.

But reads become dramatically faster.

### Best for

*   High-read systems
    
*   Analytics
    
*   Dashboards
    
*   Reporting
    

### Trade-off

More complex updates.

* * *

## 3\. Soft Delete Pattern

Never physically delete important data.

Instead:

```plaintext
is_deleted = true
deleted_at = timestamp
deleted_by = user
```

Advantages:

*   Easy recovery
    
*   Audit trail
    
*   Regulatory compliance
    
*   Prevent accidental data loss
    

Used heavily in:

*   SaaS
    
*   Healthcare
    
*   Finance
    
*   Enterprise platforms
    

* * *

## 4\. Audit Log Pattern

Track every important change.

Instead of:

```plaintext
Customer
```

Keep:

```plaintext
Customer
CustomerHistory
```

Every update becomes an immutable history record.

Useful for:

*   Debugging
    
*   Compliance
    
*   Security investigations
    
*   Data recovery
    

* * *

## 5\. Versioning Pattern

Instead of updating rows:

```plaintext
Document V1
Document V2
Document V3
```

Store multiple versions.

Perfect for:

*   Wikis
    
*   Documents
    
*   AI prompts
    
*   Configuration management
    
*   Knowledge bases
    

Git works because of versioning.

Your database can too.

* * *

## 6\. Event Sourcing

Instead of storing the latest state...

Store every event.

Example:

```plaintext
Account Created

Money Deposited

Money Withdrawn

Interest Applied
```

Current balance is reconstructed from events.

Benefits:

*   Complete history
    
*   Time travel
    
*   Replay capability
    
*   Debugging
    

Common in:

*   Banking
    
*   Trading
    
*   FinTech
    

* * *

## 7\. CQRS (Command Query Responsibility Segregation)

Separate writes from reads.

Instead of one database handling everything:

```plaintext
Write Database
↓

Event Bus
↓

Read Database
```

Reads can be optimized independently.

Advantages:

*   Faster queries
    
*   Better scalability
    
*   Independent optimization
    

Ideal when reads greatly exceed writes.

* * *

## 8\. Sharding Pattern

One database eventually becomes too large.

Split data horizontally.

Example:

```plaintext
Shard 1
Customer 1–1M

Shard 2
Customer 1M–2M

Shard 3
Customer 2M–3M
```

Benefits:

*   Horizontal scaling
    
*   Smaller indexes
    
*   Faster queries
    

Challenges:

*   Cross-shard joins
    
*   Transactions
    
*   Operational complexity
    

* * *

## 9\. Multi-Tenant Pattern

One application.

Many customers.

Common approaches:

### Shared Database

Cheapest.

```plaintext
TenantId
```

exists in every table.

### Separate Schemas

Better isolation.

### Separate Databases

Maximum security.

More operational overhead.

Choosing the right model depends on:

*   Security
    
*   Scale
    
*   Compliance
    
*   Cost
    

* * *

## 10\. Outbox Pattern

Distributed transactions are hard.

Instead of updating a database and publishing a message simultaneously:

1.  Save business data.
    
2.  Save an Outbox record in the same transaction.
    
3.  Background worker publishes events.
    
4.  Mark event as processed.
    

Benefits:

*   No lost messages
    
*   Eventual consistency
    
*   Reliable messaging
    

Widely used with:

*   Kafka
    
*   RabbitMQ
    
*   Event-driven architectures
    

* * *

## Final Thoughts

Database design isn't about memorizing normalization rules or picking the newest database technology.

It's about choosing the right pattern for the right problem.

Senior engineers understand that:

*   Every pattern has trade-offs.
    
*   Read and write workloads are rarely the same.
    
*   Scalability often starts with schema design.
    
*   Reliability is designed into the data model, not added later.
    
*   The best database architecture evolves with the business.
    

The strongest systems are built on thoughtful data models—not just clever code.

**Which database design pattern has saved you the most pain in production?**
