DB Schema
Describe your data model in English. Get production-ready schema, migrations, and diagrams.
What It Does
Takes a plain English description of your data and generates:
- SQL schema (CREATE TABLE statements with constraints)
- Migration files (for Prisma, Drizzle, Knex, Alembic, etc.)
- Entity-Relationship diagram (Mermaid or ASCII)
- Indexes (auto-detected from common query patterns)
- Seed data (realistic sample data for development)
Usage
From description:
db-schema "Users have many posts. Posts have many comments. Users can like posts."
With options:
db-schema "E-commerce with products, orders, customers" --dialect postgres --orm prisma
Options:
--dialect — postgres (default), mysql, sqlite, mongodb
--orm — raw (default), prisma, drizzle, knex, sqlalchemy, typeorm
--format — sql (default), json, markdown
--diagram — include ERD diagram: mermaid (default), ascii, none
--seed — generate seed data (default: false)
--seed-count — rows per table for seed data (default: 10)
Generation Rules
Schema Design:
- Every table gets a primary key —
id (BIGSERIAL for PG, AUTO_INCREMENT for MySQL, INTEGER AUTOINCREMENT for SQLite)
- Timestamps by default —
created_at and updated_at on every table
- Foreign keys with proper naming —
table_id references table(id)
- ON DELETE behavior — CASCADE for owned relationships, SET NULL for optional
- Proper types — use appropriate types (TEXT not VARCHAR(255) for PG, TIMESTAMPTZ not TIMESTAMP)
Relationship Detection:
| English |
Relationship |
Implementation |
| "has many" |
One-to-Many |
FK on the "many" side |
| "belongs to" |
Many-to-One |
FK on current table |
| "has one" |
One-to-One |
FK with UNIQUE constraint |
| "many to many" |
Many-to-Many |
Junction table |
| "can like/follow/tag" |
Many-to-Many |
Junction table with metadata |
Auto-Indexing:
| Pattern |
Index Type |
| Foreign keys |
B-tree index |
| Email, username |
UNIQUE index |
| Created/updated dates |
B-tree index |
| Status/type/role columns |
B-tree index |
| Full-text search fields |
GIN index (PG) / FULLTEXT (MySQL) |
| Slug/path columns |
UNIQUE index |
| Composite lookups |
Composite index |
Type Mapping:
| Concept |
PostgreSQL |
MySQL |
SQLite |
| ID |
BIGSERIAL |
BIGINT AUTO_INCREMENT |
INTEGER |
| Short text |
VARCHAR(N) |
VARCHAR(N) |
TEXT |
| Long text |
TEXT |
TEXT |
TEXT |
| Money |
NUMERIC(12,2) |
DECIMAL(12,2) |
REAL |
| Boolean |
BOOLEAN |
TINYINT(1) |
INTEGER |
| Timestamp |
TIMESTAMPTZ |
DATETIME |
TEXT |
| JSON |
JSONB |
JSON |
TEXT |
| UUID |
UUID |
CHAR(36) |
TEXT |
| Enum |
Custom TYPE |
ENUM(...) |
TEXT CHECK |
Output (SQL):
-- Generated by db-schema
-- Description: E-commerce with products, orders, customers
CREATE TABLE customers (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE products (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
price NUMERIC(12,2) NOT NULL CHECK (price >= 0),
stock INTEGER NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE orders (
id BIGSERIAL PRIMARY KEY,
customer_id BIGINT NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
status VARCHAR(50) NOT NULL DEFAULT 'pending',
total NUMERIC(12,2) NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE order_items (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE RESTRICT,
quantity INTEGER NOT NULL CHECK (quantity > 0),
unit_price NUMERIC(12,2) NOT NULL
);
CREATE INDEX idx_orders_customer_id ON orders(customer_id);
CREATE INDEX idx_orders_status ON orders(status);
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_order_items_product_id ON order_items(product_id);
ERD Output (Mermaid):
erDiagram
CUSTOMERS ||--o{ ORDERS : places
ORDERS ||--|{ ORDER_ITEMS : contains
PRODUCTS ||--o{ ORDER_ITEMS : "included in"
1---2name: db-schema3description: Generate database schemas, migrations, and ERD diagrams from plain English descriptions — supports PostgreSQL, MySQL, SQLite, and MongoDB with proper indexes and constraints.4---5
6# DB Schema
7
8Describe your data model in English. Get production-ready schema, migrations, and diagrams.
9
10## What It Does
11
12Takes a plain English description of your data and generates:
13- **SQL schema** (CREATE TABLE statements with constraints)
14- **Migration files** (for Prisma, Drizzle, Knex, Alembic, etc.)
15- **Entity-Relationship diagram** (Mermaid or ASCII)
16- **Indexes** (auto-detected from common query patterns)
17- **Seed data** (realistic sample data for development)
18
19## Usage
20
21### From description:
22```
23db-schema "Users have many posts. Posts have many comments. Users can like posts."
24```
25
26### With options:
27```
28db-schema "E-commerce with products, orders, customers" --dialect postgres --orm prisma
29```
30
31### Options:
32- `--dialect` — `postgres` (default), `mysql`, `sqlite`, `mongodb`
33- `--orm` — `raw` (default), `prisma`, `drizzle`, `knex`, `sqlalchemy`, `typeorm`
34- `--format` — `sql` (default), `json`, `markdown`
35- `--diagram` — include ERD diagram: `mermaid` (default), `ascii`, `none`
36- `--seed` — generate seed data (default: false)
37- `--seed-count` — rows per table for seed data (default: 10)
38
39## Generation Rules
40
41### Schema Design:
421. **Every table gets a primary key** — `id` (BIGSERIAL for PG, AUTO_INCREMENT for MySQL, INTEGER AUTOINCREMENT for SQLite)
432. **Timestamps by default** — `created_at` and `updated_at` on every table
443. **Foreign keys with proper naming** — `table_id` references `table(id)`
454. **ON DELETE behavior** — CASCADE for owned relationships, SET NULL for optional
465. **Proper types** — use appropriate types (TEXT not VARCHAR(255) for PG, TIMESTAMPTZ not TIMESTAMP)
47
48### Relationship Detection:
49
50| English | Relationship | Implementation |
51|---------|-------------|---------------|
52| "has many" | One-to-Many | FK on the "many" side |
53| "belongs to" | Many-to-One | FK on current table |
54| "has one" | One-to-One | FK with UNIQUE constraint |
55| "many to many" | Many-to-Many | Junction table |
56| "can like/follow/tag" | Many-to-Many | Junction table with metadata |
57
58### Auto-Indexing:
59
60| Pattern | Index Type |
61|---------|-----------|
62| Foreign keys | B-tree index |
63| Email, username | UNIQUE index |
64| Created/updated dates | B-tree index |
65| Status/type/role columns | B-tree index |
66| Full-text search fields | GIN index (PG) / FULLTEXT (MySQL) |
67| Slug/path columns | UNIQUE index |
68| Composite lookups | Composite index |
69
70### Type Mapping:
71
72| Concept | PostgreSQL | MySQL | SQLite |
73|---------|-----------|-------|--------|
74| ID | BIGSERIAL | BIGINT AUTO_INCREMENT | INTEGER |
75| Short text | VARCHAR(N) | VARCHAR(N) | TEXT |
76| Long text | TEXT | TEXT | TEXT |
77| Money | NUMERIC(12,2) | DECIMAL(12,2) | REAL |
78| Boolean | BOOLEAN | TINYINT(1) | INTEGER |
79| Timestamp | TIMESTAMPTZ | DATETIME | TEXT |
80| JSON | JSONB | JSON | TEXT |
81| UUID | UUID | CHAR(36) | TEXT |
82| Enum | Custom TYPE | ENUM(...) | TEXT CHECK |
83
84### Output (SQL):
85```sql
86-- Generated by db-schema
87-- Description: E-commerce with products, orders, customers
88
89CREATE TABLE customers (
90 id BIGSERIAL PRIMARY KEY,
91 email VARCHAR(255) NOT NULL UNIQUE,
92 name VARCHAR(255) NOT NULL,
93 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
94 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
95);
96
97CREATE TABLE products (
98 id BIGSERIAL PRIMARY KEY,
99 name VARCHAR(255) NOT NULL,
100 description TEXT,
101 price NUMERIC(12,2) NOT NULL CHECK (price >= 0),
102 stock INTEGER NOT NULL DEFAULT 0,
103 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
104 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
105);
106
107CREATE TABLE orders (
108 id BIGSERIAL PRIMARY KEY,
109 customer_id BIGINT NOT NULL REFERENCES customers(id) ON DELETE CASCADE,
110 status VARCHAR(50) NOT NULL DEFAULT 'pending',
111 total NUMERIC(12,2) NOT NULL DEFAULT 0,
112 created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
113 updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
114);
115
116CREATE TABLE order_items (
117 id BIGSERIAL PRIMARY KEY,
118 order_id BIGINT NOT NULL REFERENCES orders(id) ON DELETE CASCADE,
119 product_id BIGINT NOT NULL REFERENCES products(id) ON DELETE RESTRICT,
120 quantity INTEGER NOT NULL CHECK (quantity > 0),
121 unit_price NUMERIC(12,2) NOT NULL
122);
123
124CREATE INDEX idx_orders_customer_id ON orders(customer_id);
125CREATE INDEX idx_orders_status ON orders(status);
126CREATE INDEX idx_order_items_order_id ON order_items(order_id);
127CREATE INDEX idx_order_items_product_id ON order_items(product_id);
128```
129
130### ERD Output (Mermaid):
131```
132erDiagram
133 CUSTOMERS ||--o{ ORDERS : places
134 ORDERS ||--|{ ORDER_ITEMS : contains
135 PRODUCTS ||--o{ ORDER_ITEMS : "included in"
136```