Skip to main content

Command Palette

Search for a command to run...

10 Database Design Patterns Every Senior Engineer Should Know

Updated
4 min readView as Markdown
B
Senior Software Architect with 30+ years of experience building enterprise systems using Java, Spring Boot, and cloud-native technologies.

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:

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:

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:

Customer

Keep:

Customer
CustomerHistory

Every update becomes an immutable history record.

Useful for:

  • Debugging

  • Compliance

  • Security investigations

  • Data recovery


5. Versioning Pattern

Instead of updating rows:

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:

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:

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:

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.

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?

More from this blog

B

Bill LIao's Blog

137 posts

A technical blog on modern backend development, software architecture, and practical AI agent workflows