One-to-Many and Many-to-Many Relationships Explained
Cardinality decides where foreign keys and junction tables live. This guide explains one-to-one, one-to-many, and many-to-many relationships and how to implement each correctly.
Almost every relationship between two tables is one of three shapes: one-to-one, one-to-many, or many-to-many. Knowing which shape you are dealing with is not academic; it directly determines where the foreign keys go and whether you need an extra table. Get the cardinality right and the implementation is mechanical. Get it wrong and you end up either unable to store the data you need or forcing awkward workarounds that fight the database at every query.
This guide explains all three cardinalities and, crucially, how each maps to actual tables and keys. Many-to-many gets the most attention because it is the one that requires a junction table and the one beginners most often stumble on. You can model these relationships visually in the editor at /diagrams or the ERD tooling at /diagram-tools/erd-tool, where the crow's foot symbols make the cardinality explicit.
One-to-one: the rare case
A one-to-one relationship means each instance of entity A relates to at most one instance of entity B, and vice versa. Each User has exactly one UserProfile, and each UserProfile belongs to exactly one User. These are genuinely uncommon, and when you find one, the first question to ask is whether the two entities should simply be a single table, since one-to-one data can usually be merged without loss.
There are legitimate reasons to keep a one-to-one split. You might separate rarely-accessed or large columns (a user's long biography and avatar blob) from the frequently-queried core row for performance. You might isolate sensitive data (payment details) into its own table with tighter access controls. When you do keep them separate, implement the relationship with a foreign key on one side carrying a UNIQUE constraint, which enforces the "at most one" on both ends. The unique constraint is what distinguishes a one-to-one from a one-to-many at the schema level.
One-to-many: the common case
The one-to-many relationship is the backbone of relational design. One Customer has many Orders; one Order has many LineItems; one BlogPost has many Comments. The "one" side is the parent, the "many" side is the child, and the implementation rule is simple and universal: put a foreign key on the many side pointing at the one side. Each Order row carries a customer_id; each Comment row carries a post_id. There is no junction table and no ambiguity.
The direction of the foreign key is worth internalizing because beginners sometimes try to put a list of order IDs on the Customer, which does not work in a relational database, columns hold single values, not lists. The child points to the parent, always. Whether the foreign key is nullable expresses the optionality: a nullable customer_id would allow an order with no customer, while NOT NULL requires every order to have one. This is exactly the minimum-participation decision that crow's foot notation captures on the diagram.
Many-to-many and the junction table
A many-to-many relationship means instances on both sides can relate to many on the other. A Student enrolls in many Courses, and each Course has many Students. An Order contains many Products, and each Product appears on many Orders. You cannot implement this with a foreign key on either side, because that would only capture one direction and still only allow a single value. The solution is a third table, called a junction table (also associative, bridge, or link table), that sits between the two.
The junction table holds one row per pairing, with a foreign key to each side. An Enrollment table has a student_id and a course_id; each row means "this student is in this course." The combination of the two foreign keys is typically the primary key, which also prevents duplicate pairings. The junction table is often more than plumbing: it is the natural home for attributes of the relationship itself, like an enrollment_date or a grade, which belong to the pairing rather than to either the student or the course alone. Recognizing when you need a junction table, and that it can carry its own data, is one of the most useful instincts in database design.
A quick decision guide
When you face two entities and need to connect them, a short set of questions gets you to the right implementation every time.
- Can each side have many of the other? If yes, it is many-to-many: create a junction table.
- Can only one side have many? It is one-to-many: put a foreign key on the many side.
- Does each side have at most one of the other? It is one-to-one: foreign key with a UNIQUE constraint, or merge the tables.
- For one-to-many, the foreign key always lives on the child (many) side, never as a list on the parent.
- For many-to-many, make the pair of foreign keys the junction table's primary key to block duplicates.
- If the relationship itself has attributes (a date, a role, a quantity), they belong in the junction table.
- Use nullability on the foreign key to express whether participation is optional or mandatory.