SQLite DDL and Schema Design Cheatsheet

CREATE TABLE, constraints, generated columns, foreign keys, defaults, and schema design patterns for production SQLite databases.

View
StandardDetailedCompact
Export
Copy the compact sheet, download it, or print it.
Download
`D` dense toggle · `C` copy all

Create tables and constraints

Build durable schemas with keys, checks, and sensible defaults.

Create a basic table

Define a rowid-backed table with primary key and timestamps.

sqlANYsqlitecreate tableprimary key
sql
CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  email TEXT NOT NULL UNIQUE,
  display_name TEXT,
  created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);
Notes

`INTEGER PRIMARY KEY` aliases the rowid and is a common pattern for app tables.

Use a CHECK constraint

Validate allowed values at the database layer.

sqlANYsqlitecheckconstraints
sql
CREATE TABLE subscriptions (
  id INTEGER PRIMARY KEY,
  plan TEXT NOT NULL CHECK (plan IN ('free','premium','team')),
  status TEXT NOT NULL CHECK (status IN ('active','canceled','past_due'))
);
Notes

CHECK constraints help protect data quality even when multiple apps write to the same file.

Add a foreign key

Reference a parent table from a child table.

sqlANYsqliteforeign keycascade
sql
CREATE TABLE posts (
  id INTEGER PRIMARY KEY,
  user_id INTEGER NOT NULL,
  title TEXT NOT NULL,
  body TEXT NOT NULL,
  FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
Notes

Remember to enable foreign key enforcement per connection with `PRAGMA foreign_keys = ON;`.

Create a WITHOUT ROWID table

Optimize some composite-key tables.

sqlANYsqlitewithout rowidcomposite key
sql
CREATE TABLE locale_strings (
  locale TEXT NOT NULL,
  key TEXT NOT NULL,
  value TEXT NOT NULL,
  PRIMARY KEY (locale, key)
) WITHOUT ROWID;
Notes

Useful when the natural primary key is composite and rowid storage adds little value.

Create a generated column

Materialize or compute a derived value from another column.

sqlANYsqlitegenerated columnsjson
sql
CREATE TABLE events (
  id INTEGER PRIMARY KEY,
  payload TEXT NOT NULL,
  event_type TEXT GENERATED ALWAYS AS (json_extract(payload, '$.type')) STORED
);
Notes

Generated columns are handy with JSON payloads and can be indexed when stored.

Change schemas safely

Rename objects, add columns, and rebuild tables when needed.

Add a column

Append a new nullable or defaulted column.

sqlANYsqlitealter tablecolumns
sql
ALTER TABLE users ADD COLUMN timezone TEXT;
Notes

Adding a column is easy, but more complex schema changes often require a table rebuild.

Rename a table

Change the table name without recreating data.

sqlANYsqliterename table
sql
ALTER TABLE users RENAME TO app_users;
Notes

Useful during refactors or when aligning names with a new domain model.

Rename a column

Adjust a column name in-place.

sqlANYsqliterename column
sql
ALTER TABLE app_users RENAME COLUMN display_name TO full_name;
Notes

Modern SQLite supports renaming columns directly, which simplifies many migrations.

Rebuild a table for complex changes

Canonical pattern for dropping constraints or changing types.

sqlANYsqlitemigrationsrebuild
sql
BEGIN;
CREATE TABLE users_new (
  id INTEGER PRIMARY KEY,
  email TEXT NOT NULL UNIQUE,
  full_name TEXT,
  timezone TEXT
);
INSERT INTO users_new (id, email, full_name, timezone)
SELECT id, email, display_name, timezone FROM users;
DROP TABLE users;
ALTER TABLE users_new RENAME TO users;
COMMIT;
Notes

SQLite supports many schema changes, but rebuilds are still the practical pattern for more invasive migrations.

Recommended next

No recommendations yet.