Normalization in Database Design
I once inherited a database where a customer's address was stored in 14 different tables. Change one, you had to change all 14. Nobody ever did. The data ...
29 Apr 2024

I once inherited a database where a customer's address was stored in 14 different tables. Change one, you had to change all 14. Nobody ever did. The data was a mess within months.
Normalization prevents exactly that. It's a process of structuring your database so every piece of information lives in exactly one place. Less duplication. Fewer update anomalies. Cleaner data.
The Normal Forms
Normalization happens in stages. Each normal form builds on the previous one.
First Normal Form (1NF): Every column holds a single value. No arrays, no comma-separated lists, no repeating groups.
Bad: a phone_numbers column containing "555-1234, 555-5678".
Good: a separate phone_numbers table with one row per number.
Second Normal Form (2NF): Every non-key column depends on the entire primary key, not just part of it. This matters when you have composite primary keys.
If your primary key is (order_id, product_id) and you store product_name in that table, you've violated 2NF. The product name depends on product_id alone, not the full key. Move it to a products table.
Third Normal Form (3NF): No non-key column depends on another non-key column. Every column depends directly on the primary key.
If you store zip_code and city in a customers table, and city is determined by zip_code (not the customer ID), that's a transitive dependency. Extract it into a zip_codes table.
Before and After
Denormalized:
interface Order {
id: number;
customerName: string;
customerEmail: string;
customerAddress: string;
productName: string;
productPrice: number;
quantity: number;
}
If a customer changes their email, you update every order row. Miss one and your data is inconsistent.
Normalized:
interface Customer {
id: number;
name: string;
email: string;
address: string;
}
interface Product {
id: number;
name: string;
price: number;
}
interface Order {
id: number;
customerId: number;
productId: number;
quantity: number;
}
Customer email changes in one place. Every order references it through a foreign key. Data stays consistent automatically.
When to Break the Rules
Normalization optimizes for data integrity and write efficiency. But it costs read performance. Every lookup now requires JOINs across multiple tables.
For read-heavy applications, strategic denormalization can be the right call. Store customerName directly on the Order table if you always display them together and rarely update names.
The key word is "strategic." Denormalize with intention, not laziness. Know what you're trading: you're accepting potential inconsistency in exchange for faster reads.
Most applications should start normalized and selectively denormalize based on measured performance bottlenecks. Not the other way around.