CorriDraw CorriDraw
Tutorial

ER Diagrams 101: Crow's Foot Notation From Scratch

A complete beginner's guide to Entity-Relationship diagrams. Learn what entities, attributes, keys, relationships, and cardinality actually mean — then read crow's foot notation fluently and draw your first schema, concept by concept, with an illustration for every idea.

PV

Palakorn V.

Product Lead

18 min read
ER Diagrams 101: Crow's Foot Notation From Scratch

What Is an ER Diagram?

An Entity-Relationship diagram — "ER diagram" for short — is a picture of the data that lives inside a system. Before anyone writes a single CREATE TABLE statement, before an API gets sketched, before screens get wireframed, a thoughtful team sits down and draws one. It's the blueprint of everything the software will remember.

Here is what a small ER diagram looks like. Two boxes — those are the "things" the system stores — connected by a line — that's the relationship between them. The small symbols at each end of the line explain how many of each thing can exist on that side.

USER id email name ORDER id user_id total places
A two-entity ER diagram. Read it as: "one user places zero or many orders; every order belongs to exactly one user."

Three ingredients do all the work: entities (the things), attributes (what each thing knows), and relationships (how things connect, and how many connect to how many). This article teaches you those three ingredients from scratch, using crow's foot notation — the dialect used by almost every modern database tool, and the one that reads most naturally once you learn it. No prior database knowledge required. By the last section, you will be able to read any ER diagram you come across and draw your own for any project you touch.

Why Bother Drawing One?

Databases are easy to start and brutal to refactor. Pick the wrong shape on day one and you'll be living with it — or paying down that technical debt — for years. An ER diagram is the cheapest possible way to catch the wrong shape before writing any code.

Concretely, a twenty-minute ER diagram session tends to surface three kinds of problems that would otherwise ship as bugs:

  • Missing things. "Wait, if two users can co-own a project, where does that co-ownership live?" Right — you need a whole entity nobody had thought of yet.
  • Wrong cardinalities. "Can a customer have more than one shipping address?" Yes, obviously, but the first draft put address columns directly on CUSTOMER.
  • Broken paths. "How does a comment find its post author?" The diagram either shows the path or it doesn't. If it doesn't, you're about to write a bug.

You don't need a degree in database theory to benefit. You just need to draw a rectangle, a line, and a few small symbols at the ends of that line. The rest of the article teaches each piece.

The Entity: A Thing Worth Storing

The first word in "Entity-Relationship diagram" is entity. An entity is any thing your system cares about enough to remember. If you're building a blog, the entities are: user, post, comment, tag. If you're building a pizza-ordering app: customer, pizza, order, driver. If you're building an airline: passenger, flight, seat, ticket.

A simple test: if you'd expect the product to have a list of something, that something is probably an entity. "Show me my posts." "Show me active orders." "Show me all flights from LAX on Friday." Each of those lists is populated from an entity.

In a diagram, every entity is drawn as a rectangle. The name goes at the top, in ALL CAPS — that's a long-standing convention that keeps entity names visually distinct from everything else on the canvas. Below the name, a horizontal divider, and below the divider, the list of what that entity knows. For now, start with just the name:

USER
The simplest possible entity: a rectangle, a divider near the top, and a name.

That's it. A rectangle with a name. The world's smallest ER diagram is a single entity — not very useful, but legal. From here, everything else builds up.

Two common mistakes to avoid:

  • Don't confuse an entity with an instance. The entity is USER; a single user named "Alice" is an instance of that entity. Your diagram shows the shape of users in general, not any one specific user.
  • Use the singular form. Write USER, not USERS; ORDER, not ORDERS. The entity is the idea of "a user" — the plural shows up when you have many of them, not when you name them.

Attributes: What You Know About Each Thing

An empty rectangle is a good start, but every entity carries facts — the pieces of data you record for each one. Those facts are called attributes. A user has an email, a display name, a date they signed up. An order has a total, a status, a placed-at timestamp. Those go inside the entity's body, below the divider, one attribute per line.

USER id email display_name created_at is_admin
An entity with five attributes. Each line is one piece of data every user has.

You can get as detailed as you want. Some diagrams list only the attribute names, as above. Others also include the data type (email: string, created_at: timestamp), and the richest ones add length limits or notes. For a first diagram, names alone are fine — a too-detailed ER diagram becomes hard to read and quickly falls out of sync with the code.

One guideline: if a fact about an entity has its own facts, that fact is probably an entity of its own. "Address" is a good example — it has street, city, state, zip, country. Don't cram those into the user entity. Pull address out into its own ADDRESS entity and connect it to USER with a relationship. We'll cover relationships next.

Keys: PK, FK, and UK

Three short tags show up next to attributes often enough that they deserve their own section: PK, FK, and UK. They stand for primary key, foreign key, and unique key, and they describe what job each attribute does beyond just holding data.

  • Primary Key (PK) — the attribute that uniquely identifies this row. Every entity has exactly one PK. Usually it's called id and is a number or a UUID. "Give me user 42" works because id is a PK.
  • Foreign Key (FK) — an attribute that points at another entity's primary key. If POST has a column called author_id that holds a USER.id, then author_id is an FK. Foreign keys are how entities find each other.
  • Unique Key (UK) — an attribute that is not the primary key but must still be unique across the whole entity. A user's email is the classic example: it's not the ID you pass around internally, but no two users can share it.
USER id PK email UK display_name created_at POST id PK author_id FK title published_at The FK on POST holds a USER's PK value — that's how a post "knows" its author.
Primary keys (blue) uniquely identify rows. Foreign keys (red) reference another entity's primary key. Unique keys (green) are non-primary but still unique.

You can think of it like phone numbers. The primary key is a person's phone number — a unique handle everyone else uses to reach them. A foreign key is someone else's address book entry pointing at that number: "Mom → 555-1234". The entry in the address book isn't the identity; it's just a pointer. Unique keys are like email addresses: a second way to identify someone, also unique, but not the "official" one the system uses internally.

In a diagram, these tags are just plain text next to the attribute. Some drawing tools render them as little coloured badges, others as plain letters in the margin. Either way works. The tags are for humans — they help whoever reads the diagram understand the role each attribute plays.

The Relationship: A Line Between Two Entities

An isolated entity isn't very interesting. The interesting part of every data model is how the entities connect. A relationship is a line between two entities, and it answers the question: "how are these two things related to each other in the real world?"

The simplest relationship is just a line with a name on it. No symbols, no cardinality, just the idea that these two entities touch each other somehow:

AUTHOR POST writes
A bare relationship: "an author writes a post". True, but vague. We don't yet know whether an author writes one post or many, or whether every post must have an author.

The label on the line is a short verb phrase that describes the relationship from one side. "Writes". "Belongs to". "Enrolls in". "Tagged with". Read it in the direction of the line: "AUTHOR writes POST". Good labels make the diagram self-documenting; bad or missing labels make the reader squint.

But the line alone is underspecified. Does each author write exactly one post? Many posts? Can a post have two authors? That's where the symbols at each end come in.

Cardinality: The "How Many" Question

Cardinality is a fancy word for count. In an ER diagram, it answers "how many of this side can relate to the other side?" Every relationship has two cardinality answers — one from each side's point of view.

Consider the author-writes-post relationship from above. From the author's side: how many posts can one author write? Any number. From the post's side: how many authors does one post have? Exactly one. Those are two different counts, and both matter.

Cardinality has two parts: an upper bound (the most) and a lower bound (the least). Four combinations show up everywhere:

  • Exactly one — at least one, at most one. The post must have an author, and only one. (lower: 1, upper: 1)
  • Zero or one — at most one, but it's optional. A user may have a profile photo — or not. (lower: 0, upper: 1)
  • One or many — at least one, possibly more. An invoice must have at least one line item. (lower: 1, upper: many)
  • Zero or many — optional, unlimited. An author may have written no posts yet, or a hundred. (lower: 0, upper: many)

Here's the same author-post relationship, but with both sides drawn out at the instance level. Each arrow is one real-world "writes" link. Notice how one author row connects to multiple post rows, but every post row connects back to exactly one author.

AUTHOR rows 1 Alice 2 Bruno 3 Chen 4 Dana (no posts yet) POST rows 101 Getting started 102 Why ER diagrams 103 Advanced queries 104 My week in NYC 105 Pizza recipe Alice wrote 2 posts. Bruno wrote 3. Chen wrote 0. Dana wrote 0. Every post points back at exactly one author.
Four authors, five posts, five "writes" links. The author side is zero-or-many (Chen and Dana have zero); the post side is exactly-one.

This is the mental model the abstract diagram is trying to capture — one row per entity on each side, and lines between them that obey the cardinality rules. The crow's foot symbols let you express those rules without drawing every instance.

The Crow's Foot Vocabulary

Crow's foot notation uses three basic symbols and combines them into a small vocabulary. Learn the three, and the combinations follow.

  • A short bar perpendicular to the line means one.
  • A three-line fan that looks like a bird's foot (hence the name) means many.
  • A small circle means zero — the relationship is optional on that side.

You put one of these at each end of the relationship line, close to the entity you're describing. Two markers on one side — one closer to the entity, one farther — let you express both the upper and the lower bound together:

  • The inner marker (closest to the entity) encodes the upper bound: the most.
  • The outer marker (farther from the entity) encodes the lower bound: the least.

With three symbols and two slots, here is the full vocabulary you will ever need:

Exactly one min 1, max 1  (mandatory, single) One or many min 1, max many  (mandatory, multiple) Zero or one min 0, max 1  (optional, single) Zero or many min 0, max many  (optional, multiple) Reading rule: inner (closer to entity) = maximum outer (farther from entity) = minimum The thick grey bar on the right of each example represents the entity edge.
The four practical cardinalities, each made by combining a "max" symbol (inner, near the entity) with a "min" symbol (outer, farther out).

Exactly-one and one-or-many are the mandatory flavours — the outer marker is a bar, meaning the relationship must exist. Zero-or-one and zero-or-many are the optional flavours — the outer marker is a circle, meaning the relationship can be absent.

A small practical tip: the difference between "exactly one" and "zero or one" is whether the outer bar is a bar or a circle. Beginners often miss this, and it matters. "A user must have an email" (mandatory) is a different database schema than "a user may have an email" (optional), and it's the difference between a NOT NULL column and a nullable one.

How to Read a Relationship, Both Ways

Every relationship reads in both directions, and you should always read it in both. If you only check one side, you might write the wrong schema.

Here's a relationship with annotations. The markers at each end describe the other side. Pick one entity, look at the markers near the opposite entity, and read that side's cardinality.

USER ORDER places markers near USER describe "how many USERs per ORDER" exactly one markers near ORDER describe "how many ORDERs per USER" zero or many Reading left-to-right: "a user places zero or many orders" Reading right-to-left: "an order is placed by exactly one user"
The markers at each end describe the opposite entity. Always read both directions — they tell you different things.

Two useful sentences come out of reading the relationship both ways:

  1. "A user places zero or many orders." (from USER's side)
  2. "Every order is placed by exactly one user." (from ORDER's side)

If either sentence sounds wrong for the system you're modelling, the diagram is wrong — fix the markers. If both sound right, the diagram captures the rule correctly. This two-sentence test catches nearly every cardinality mistake.

The Three Classic Relationship Types

Once you can read cardinality, you can classify almost every real-world relationship as one of three types: one-to-one, one-to-many, and many-to-many. Each has its own look in crow's foot notation and its own translation into database tables.

One-to-One (Rare)

Exactly one on both sides. One of these relates to one and only one of those. The textbook example is a person and their passport: each person has at most one valid passport; each passport belongs to exactly one person.

PERSON PASSPORT holds a person holds zero or one passport; a passport belongs to exactly one person
One-to-one. Note the optional side on the passport end — not everyone has a passport.

One-to-one relationships are rare in practice because if two entities always go together, you can usually just merge them into a single entity. People still draw them when the two halves have different security, storage, or lifecycle concerns — user account and profile photo, employee and social-security-number record, that sort of thing.

One-to-Many (The Workhorse)

One on one side, many on the other. This is the most common relationship in any database. A bank has many accounts; each account belongs to one bank. An author has many posts; each post has one author. A parent comment has many reply comments; each reply has one parent.

AUTHOR POST writes an author writes zero or many posts; every post has exactly one author
One-to-many. The "many" side (POST) holds a foreign key pointing at the "one" side (AUTHOR).

In the database, a one-to-many relationship translates to a foreign key on the "many" side. The POST table gets an author_id column that holds a USER.id. No extra table, no joining weirdness — just a column.

Many-to-Many (Needs a Junction)

Many on both sides. A student takes many courses; a course has many students. A post has many tags; a tag is applied to many posts. A movie has many actors; an actor stars in many movies. You can't express this with a single foreign key — neither side has a single "parent" to point at.

STUDENT COURSE enrolls in a student enrolls in zero or many courses; a course has zero or many students
Many-to-many as a single line. Valid in the diagram, but hides a missing table.

In a real database, a many-to-many relationship needs a third entity — a junction table — that records each individual connection. Think of it as the "membership" card that says "student 7 is enrolled in course 204". Each row in the junction is one enrollment, and the junction turns one many-to-many into two simpler one-to-many relationships:

STUDENT ENROLLMENT student_id FK course_id FK enrolled_at COURSE has of
The same many-to-many, resolved with a junction entity. Two one-to-many relationships replace one many-to-many, and you get a natural place to attach extra facts about each connection — like when the student enrolled.

The junction also gives you a natural home for any data that belongs to the connection itself rather than to either side. "When did student 7 enroll in course 204?" That enrolled_at timestamp isn't a property of the student or of the course — it's a property of the enrollment. The junction entity is where it lives.

When designing a schema, draw the many-to-many as a single line first to see the logic, then resolve it to a junction when you're ready to think about the physical tables. Both forms show up in real diagrams.

Your First ER Diagram: A Tiny Blog

Time to put it all together. Let's model a tiny blogging platform. Users write posts, other users leave comments, and posts can be tagged. We'll build the diagram in four passes, the same way you would in real life.

Step 1 — List the entities

Start by brainstorming the nouns that show up when you describe the product. "Users write posts." "Posts have comments." "Posts are tagged." Four nouns: USER, POST, COMMENT, TAG. Each becomes a rectangle. At this stage there are no attributes and no relationships — just the shell of the diagram.

Step 2 — Fill in the attributes

For each entity, list the facts you need to remember. Stick to what matters for the core product; you can always add more later.

  • USER: id PK, email UK, display_name, created_at
  • POST: id PK, author_id FK, title, body, published_at
  • COMMENT: id PK, post_id FK, author_id FK, body, created_at
  • TAG: id PK, slug UK, name

Step 3 — Find the relationships

Walk through the product's behaviour and find every pair of entities that "touch". For each pair, write a short verb phrase:

  • A user writes posts.
  • A user writes comments.
  • A post has comments.
  • A post is tagged with tags.

Step 4 — Add cardinality

For each relationship, apply the two-sentence test from earlier. Ask "how many of A per B, and how many of B per A?"

  • USER → POST: a user writes zero or many posts; a post has exactly one author. That's one-to-many.
  • USER → COMMENT: a user writes zero or many comments; a comment has exactly one author. Same shape — one-to-many.
  • POST → COMMENT: a post has zero or many comments; a comment belongs to exactly one post. Also one-to-many.
  • POST ↔ TAG: a post can have many tags; a tag can be on many posts. Many-to-many.

Put it all on the canvas and the diagram looks like this:

The complete blog schema: USER, POST, COMMENT, and TAG entities. USER writes zero-or-many POSTs; USER wrote zero-or-many COMMENTs; POST has zero-or-many COMMENTs; POST is tagged with zero-or-many TAGs (many-to-many). Every cardinality shown in crow's-foot notation.
The complete blog schema. Four entities, four relationships, every cardinality labelled in crow's-foot notation.

This is a real schema. You could hand it to a backend engineer and they would build the same tables. You could hand it to a frontend engineer and they would know which API endpoints to expect. You could hand it to a PM and they would understand the feature's data shape in sixty seconds. That's the value of a good ER diagram: one picture, three audiences, zero confusion.

Expressing ER Diagrams as Text

Diagrams are visual, but there is a widely used text format for ER diagrams too — the Mermaid syntax. Mermaid is understood by GitHub, GitLab, Notion, Obsidian, and most developer documentation pipelines, and it saves you from drawing every time you want to show a schema. The grammar is compact: one line per relationship, then one block per entity for the attributes.

Here is the tiny blog schema written in Mermaid:

erDiagram
  USER    ||--o{ POST    : writes
  USER    ||--o{ COMMENT : wrote
  POST    ||--o{ COMMENT : has
  POST    }o--o{ TAG     : "tagged with"
  USER {
    uuid id PK
    string email UK
    string display_name
    timestamptz created_at
  }
  POST {
    uuid id PK
    uuid author_id FK
    string title
    text body
    timestamptz published_at
  }
  COMMENT {
    uuid id PK
    uuid post_id FK
    uuid author_id FK
    text body
    timestamptz created_at
  }
  TAG {
    uuid id PK
    string slug UK
    string name
  }

Reading that block should now feel natural. The ||--o{ between USER and POST is the text form of "exactly one writes zero or many" — exactly the crow's foot markers you just learned, typed out character by character. Mermaid is a useful skill to pick up alongside the visual notation: one way for quick drafts in the middle of a design doc, the other for polished versions that end up on a whiteboard or in a slide.

Common Beginner Mistakes

Five mistakes show up in almost every first ER diagram. Knowing the shape of each one in advance helps you spot them in your own work.

  • Confusing the entity with an instance. The entity is USER (the idea of "a user"), not "Alice". The diagram describes a type, never a specific row. If you catch yourself drawing rectangles for individual people, zoom out a level.
  • Forgetting the junction on many-to-many. It's fine to draw POST }o--o{ TAG at sketch time, but when you sit down to build the tables, you need a third entity (POST_TAG) to hold the individual connections. Many-to-many without a junction isn't a database design — it's a todo.
  • Getting the cardinality direction backwards. The markers near entity B describe how many Bs exist per A, not the other way around. If the diagram reads wrong, swap which end has which marker, not the markers themselves.
  • Burying relationships inside attributes. If an entity has an attribute like addresses: list of strings, that's a hidden relationship — pull it out into its own ADDRESS entity. The rule of thumb: if a value has its own facts or can repeat, it's an entity.
  • Over-detailing too early. A 40-entity diagram with every attribute and data type is impressive and completely unreadable. Start with five to eight entities and the facts that matter for the current decision. You can always add more later; you can't easily take them away once the diagram becomes a wall.

Where to Go Next

You now know enough to read any ER diagram and draw your own for almost any domain. Three natural next steps once the basics click:

  • Translate to SQL. Each entity becomes a CREATE TABLE. Each one-to-many relationship becomes a foreign key column on the "many" side. Each many-to-many becomes a junction table with two foreign keys. Do this translation a few times by hand and the diagram-to-schema mapping becomes second nature.
  • Learn one alternative notation. IDEF1X and UML class diagrams are the other two dialects you'll encounter in the wild. Both encode the same ideas you just learned; only the symbols differ. A half hour with either is enough to become conversationally fluent.
  • Model a real project. Pick something you use every day — a calendar, a chat app, a to-do list — and try to reverse-engineer its ER diagram. The parts that feel hard are the parts where the real app made a non-obvious design choice. Those are the most educational cases.

Diagrams are cheap. Rebuilds are not. Ten minutes in a drawing tool before a single line of code is the best return on investment any engineering workflow offers — and crow's foot notation is the tightest, most-readable way to draw one. The rest is just practice.

A Note on Tools

Everything in this article is about the notation itself, and it works the same in any drawing tool: pencil and paper, a whiteboard, Figma, Miro, or anywhere else you can draw a rectangle and a line. If you'd like a tool that has the ER entity shape, all the crow's foot markers, and a Mermaid importer built in — so the steps in this article take seconds rather than minutes — CorriDraw is one option; it's the tool you're reading this on. But the ideas transfer: you now know how to read and draw an ER diagram anywhere.

Share this story
It’s
Free!
Forever
Let’s draw together

Ready to start collaborating ?

Join thousands of teams using CorriDraw for their visual collaboration needs.