Supabase — New Table Checklist
Every table exposed through Supabase must have RLS enabled, proper constraints, indexes, and be fully documented before it is used in production.
Back to Supabase Checklist
0/0 completed
1. Before You Create the Table
2. Table Schema
Required Columns — Every Table
| Column | Type | Notes |
|---|---|---|
id |
uuid DEFAULT gen_random_uuid() |
Primary key |
created_at |
timestamptz DEFAULT now() |
Always included |
updated_at |
timestamptz DEFAULT now() |
Always included |
Workspace-Scoped Tables — Multi-Tenant
| Column | Type | Notes |
|---|---|---|
workspace_id |
uuid NOT NULL REFERENCES workspaces(id) |
Required for any tenant-scoped table |
User-Owned Records
| Column | Type | Notes |
|---|---|---|
created_by |
uuid NOT NULL REFERENCES auth.users(id) |
Track who created the record |
Soft Delete — If Applicable
| Column | Type | Notes |
|---|---|---|
deleted_at |
timestamptz DEFAULT NULL |
NULL = not deleted, timestamp = deleted |
3. Naming Standards
4. Constraints
Example CHECK Constraint
CHECK (status IN ('active', 'inactive', 'archived'))
CHECK (percentage >= 0 AND percentage <= 100)
ON DELETE Decision Guide
| Scenario | Use |
|---|---|
| Child records have no meaning without parent | CASCADE |
| Child records should be preserved for audit | RESTRICT or SET NULL |
| Foreign key is optional reference | SET NULL |
| Default — block parent deletion | RESTRICT |
5. Indexes
Composite Index Example
CREATE INDEX ON projects (workspace_id, status);
6. RLS Setup
RLS Policy Patterns
-- SELECT: workspace members only
CREATE POLICY "workspace_members_select"
ON projects
FOR SELECT
USING (
workspace_id IN (
SELECT workspace_id
FROM workspace_members
WHERE user_id = auth.uid()
)
);
-- INSERT: workspace members only, sets created_by automatically
CREATE POLICY "workspace_members_insert"
ON projects
FOR INSERT
WITH CHECK (
workspace_id IN (
SELECT workspace_id
FROM workspace_members
WHERE user_id = auth.uid()
)
AND created_by = auth.uid()
);
-- UPDATE: only creator or admin
CREATE POLICY "owner_or_admin_update"
ON projects
FOR UPDATE
USING (
created_by = auth.uid()
OR EXISTS (
SELECT 1
FROM workspace_members
WHERE workspace_id = projects.workspace_id
AND user_id = auth.uid()
AND role = 'admin'
)
);
-- DELETE: only admin
CREATE POLICY "admin_delete"
ON projects
FOR DELETE
USING (
EXISTS (
SELECT 1
FROM workspace_members
WHERE workspace_id = projects.workspace_id
AND user_id = auth.uid()
AND role = 'admin'
)
);
7. Audit Fields
Auto-Update Trigger for updated_at
CREATE OR REPLACE FUNCTION update_updated_at() RETURNS TRIGGER AS $$ BEGIN NEW.updated_at = now(); RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER set_updated_at BEFORE UPDATE ON your_table_name FOR EACH ROW EXECUTE FUNCTION update_updated_at();
8. Migration File
9. Documentation
Before Marking Done
10. New Table Checklist
Naming
Constraints
Indexes
RLS
Migration & Documentation
Practice Task
Apply what you learned by creating a real table with the correct schema, constraints, indexes, soft delete, and migration file.
Open Task 01: Create the Projects Table