# Relationships

> Draw relationships in Schemity using crow's foot notation. Understand 1:1, 1:N, and N:N relationships, optionality, referential actions, and self-references in your ERD.

Source: https://schemity.com/doc/relationships/

Relationships connect your entities and express how rows relate. Schemity draws them in **crow's foot notation**, the notation most software engineers read fastest.

## How do I create a relationship?

Draw a relationship between two entities and Schemity creates the foreign key field on the child entity and the connector between them. In the relation dialog you set:

- **Relation type** - `1:N`, `1:1`, or `N:N`.
- **On delete** and **On update** - the referential actions: `CASCADE`, `SET NULL`, `RESTRICT`, `NO ACTION`, or `SET DEFAULT`. SQL Server has no `RESTRICT`, so it is not offered there, and MySQL is not offered `SET DEFAULT`: MySQL accepts the clause and then refuses the delete exactly as `RESTRICT` does, which [schema lint](https://schemity.com/doc/schema-lint/) reports on a key read from the database.
- **Description** - an optional sentence saying what the relationship means, such as `places` for a customer and an order.

Choosing `SET NULL` for either action makes the foreign key's columns nullable in the same edit and draws the relationship as optional, since the action writes `NULL` into those columns. Primary key columns cannot hold `NULL` and are left as they are. A key read from a database or imported from SQL can still pair `SET NULL` with a `NOT NULL` column, and [schema lint](https://schemity.com/doc/schema-lint/) reports it: PostgreSQL and SQLite accept that key and fail the delete that fires it, while MySQL and SQL Server refuse the key. For which action fits which relationship, see [ON DELETE SET NULL vs CASCADE vs RESTRICT](https://schemity.com/blog/postgres-on-delete-set-null-vs-cascade/).

Changing an action on a relationship that already exists in the database replaces the foreign key. On PostgreSQL the migration drops the key and adds it again, since `ALTER TABLE` cannot change a key's actions in place. [Impact analysis](https://schemity.com/doc/impact-analysis/) reports that step before it runs.

## Can a relationship keep rows inside one tenant?

Yes, since v2.14.5. When the parent table has a unique constraint that holds its primary key plus a tenant column, such as `UNIQUE (company_id, id)` on `members`, a relationship drawn to it becomes a composite foreign key over both columns: `(company_id, member_id)` referencing `members (company_id, id)`. The database then refuses a row that points at another tenant's member. The child's own `company_id` is reused when it has one of the same type, and added as `NOT NULL` when it has none; the relation dialog shows that row locked, with a tooltip saying which. Tick **Reference members.id only** for a table that does not belong to a tenant, and the relationship references the primary key alone.

On PostgreSQL 15 and later, `SET NULL` on such a key is written as `ON DELETE SET NULL (member_id)`, so deleting a member clears only the member column and the row keeps its tenant. Other databases have no such clause and would clear the shared column too, so there the relationship is refused with that explanation and you pick `CASCADE`, `RESTRICT` or `NO ACTION` instead. For when to use this pattern rather than row-level security, see [Composite foreign keys vs row-level security](https://schemity.com/blog/postgres-composite-foreign-key-vs-row-level-security/).

## Can a relationship say what it means?

Yes. A description written in the relation dialog is drawn along the line itself, so `one row per shipment, splits get their own` is read by everyone who looks at the diagram, not only by whoever thinks to click. The text follows the route when you reshape the line or move either entity, and SVG exports draw it too. Mermaid, PlantUML, and D2 exports write it as the label on the relationship line; in Mermaid, a relationship without a description is labelled with its foreign key name instead.

## Can I draw a relationship the database does not declare?

Yes. Switch the relation dialog to **Virtual relation** to document a dependency that exists only in column names, without adding a foreign key to the database. Schemity can also infer these from names like `user_id` when a schema opens with no declared foreign keys. See [Virtual & Inferred Relations](https://schemity.com/doc/virtual-relations/).

## How do I read crow's foot notation?

The symbols at each end show cardinality and optionality:

- A single bar means "one".
- The crow's foot (three prongs) means "many".
- A circle means "optional" - shown at the child end when the foreign key field is nullable.

So a connector with a bar on the parent and a crow's foot on the child reads as **one-to-many**.

A **bold crow's foot** means the relationship's `ON DELETE` is set to `CASCADE`: deleting the parent row deletes these child rows too. The signal is line weight rather than a warning color on purpose - a cascade is a design decision, not an error, so a bold end marks a relationship that deserves special care, not one that needs fixing.

## What is the difference between 1:N and N:N relationships?

Understanding **1:N vs N:N relationships** is the key modeling decision:

- **One-to-many (1:N)** - one parent row relates to many child rows. A user has many orders. This is a direct foreign key.
- **One-to-one (1:1)** - at most one row on each side.
- **Many-to-many (N:N)** - rows on both sides relate to many on the other. Students and courses. A relational database cannot store this directly; it needs a junction entity - see [Junction Tables](https://schemity.com/doc/auto-junction-tables/).

## How do I create a self-referencing relationship?

An entity can relate to itself - an `employees.manager_id` pointing back at `employees.id`. Draw the relationship from the entity to its own key.

## How do I trace a relationship in a crowded diagram?

In a crowded diagram it can be hard to see where a connector starts and ends. Two features make any relationship traceable:

- **Click to highlight** - click a relationship and Schemity highlights the whole line together with the fields it connects: the foreign key field on the source entity and the primary key field on the target entity. Both ends of the relationship are instantly visible, no matter how many lines cross it.
- **Color inheritance** - [set a color on an entity](https://schemity.com/doc/tables-and-fields/) and every relationship originating from it inherits that color, so the color alone tells you which entity a line comes from.

Where two relationship lines cross, one hops over the other with a small arc, so a crossing is never mistaken for a connection.

## What happens to foreign keys when I copy entities?

When you copy or duplicate entities, Schemity is smart about foreign keys: relationships to entities you also copied are preserved with remapped names, while relationships to entities left behind are dropped and the field becomes a plain field.

## Routing

To route every connector at once, choose **Route Relations** from the layout menu in the control bar: lines run around the tables, cross each other less, and share corridors as parallel lanes. To control how a single connector is drawn, add [Custom Waypoints](https://schemity.com/doc/custom-waypoints/).

## Next

Add finer rules with [Check Constraints & Composite Unique](https://schemity.com/doc/check-constraints-composite-unique/).
