Constraints — write-time integrity

Constraints reject bad writes before they land. UNIQUE prevents duplicate values on a field; NOT NULL requires the field to be present; FOREIGN KEY links to another entity and governs what happens when the referenced row is deleted (CASCADE, RESTRICT, or SET NULL).

How it works

flowchart TD
    W["db.create or update"] --> Q{Check all
constraints} Q -- UNIQUE collision --> X1[reject: unique] Q -- NOT NULL missing --> X2[reject: not_null] Q -- FK parent absent --> X3[reject: foreign_key] Q -- all pass --> OK[write lands] D["db.delete parent"] --> DQ{FK on_delete?} DQ -- CASCADE --> D1[delete children too] DQ -- RESTRICT --> D2[reject if children] DQ -- SET NULL --> D3[null out FK on children] style X1 fill:#ffcdd2,stroke:#c62828 style X2 fill:#ffcdd2,stroke:#c62828 style X3 fill:#ffcdd2,stroke:#c62828 style D2 fill:#ffcdd2,stroke:#c62828 style OK fill:#c8e6c9,stroke:#2e7d32 style D1 fill:#c8e6c9,stroke:#2e7d32 style D3 fill:#c8e6c9,stroke:#2e7d32

Try it — a five-step tour

  1. The Add constraint form is pre-filled with a UNIQUE constraint on users.email. Click Add — the constraint appears in the list to the right.
  2. Scroll to Scenario playground and click Seed data to create two users with the same email. The second insert is rejected (log shows ✗ unique constraint violation).
  3. Switch the constraint type to Foreign key. Source is pre-filled: posts.author_id → users.id, on delete CASCADE. Click Add, then Setup FK demoDelete parent. The child posts vanish with the user.
  4. Change on-delete to RESTRICT, reset the demo, and try to delete the parent again. The delete is rejected while children exist.
  5. Click Run all tests at the bottom to see all six scenarios exercised automatically.

Add constraint

UNIQUE

Pick one or more fields to require unique values across the entity.

Defined constraints 0

No constraints yet. Use the form on the left.

Scenario playground

Pre-built scenarios that show each constraint in action. Each runs in isolation — start with Reset demo data between runs if you want a clean slate.

UNIQUE: reject duplicate email

Adds a UNIQUE constraint on users.email, inserts Alice, then tries Bob with Alice's email.

FOREIGN KEY: valid / invalid parent

Adds FK posts.user_id → users.id (RESTRICT), creates a user, then tries to add posts referencing real and fake user ids.

CASCADE: delete parent wipes children

Adds FK comments.post_id → posts.id (CASCADE), creates a post with two comments, then deletes the post — comments vanish.

RESTRICT: delete is blocked while children exist

Adds FK comments.post_id → posts.id (RESTRICT), creates a post with one comment, then tries to delete the post — rejected.

Data view

IDData

Automated test suite

Run all tests performs six scenarios in a fresh namespace (prefix test_) and reports each as pass or fail:

  1. UNIQUE on test_users.email rejects duplicate inserts
  2. NOT NULL on test_users.name rejects rows without name
  3. Valid FK insert succeeds
  4. Invalid FK insert is rejected
  5. CASCADE delete removes all children
  6. RESTRICT delete is blocked while children exist
Click the button to run.

Log