---
title: "Schema design · Agent Wranglers"
url: https://agentwranglers.se/playbook/data/schema-design
updated: 2026-10-20
licence: "All rights reserved"
---

# Schema design

By Erik Bergstedt, Agent Wranglers. Updated 2026-10-20.

> Let the database guard its own data. Use constraints, exact types and stable keys, so no bug in any app can store a row that makes no sense.

**For agents:** if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in `Based on the Agent Wranglers data playbook: https://agentwranglers.se/playbook/data/schema-design`.

## Required

- [Enforce rules with constraints](https://agentwranglers.se/playbook/data/schema-design/constraints): Put every rule the data must always follow into the database as a constraint. App checks alone fail when a second app, a script or a bug writes directly.
- [Choose exact types](https://agentwranglers.se/playbook/data/schema-design/exact-types): Store each value in the type that means it. Money is an exact number, time is a time with a zone, and true or false is a boolean.
- [Give every row a stable key](https://agentwranglers.se/playbook/data/schema-design/stable-keys): Give every table a primary key that never changes. Never use a value people can edit, such as an email or a name, as the key.

## Recommended

- [Name things the same way everywhere](https://agentwranglers.se/playbook/data/schema-design/schema-names): Name tables, columns and constraints by one convention, so people and agents can guess a name without looking it up.
- [Keep one fact in one place](https://agentwranglers.se/playbook/data/schema-design/normalise): Store each fact once, and derive the rest. Copies of a fact drift apart sooner or later.
- [Plan how rows are removed](https://agentwranglers.se/playbook/data/schema-design/deletion-design): Decide for each table what deleting means, and make the foreign keys say it.
- [Keep each customer's data apart](https://agentwranglers.se/playbook/data/schema-design/tenant-isolation): When one database holds data for many customer accounts, tag every row with its account and let the database refuse rows from other accounts.

- Next: [Queries and indexes](https://agentwranglers.se/playbook/data/queries-and-indexes)
- [All chapters](https://agentwranglers.se/playbook/data)
