-
Notifications
You must be signed in to change notification settings - Fork 2
Foreign Key Dependencies
Understanding and analyzing foreign key relationships and dependencies in D1 databases.
Foreign Key Dependencies viewer helps you understand table relationships before performing destructive operations. It shows which tables reference each other through foreign key constraints and what will happen when data is deleted.
Key Features:
- Dependency Analysis - Automatic foreign key detection
- Bidirectional View - See both inbound and outbound dependencies
- Row Count Estimates - Know how many rows will be affected
- ON DELETE Behavior - Understand CASCADE, RESTRICT, SET NULL actions
- Visual Indicators - Color-coded by severity
- Mandatory Confirmation - Prevents accidental data loss
Related Features:
- Foreign Key Visualizer - Interactive graph-based constraint management with visual editing
- Cascade Impact Simulator - Detailed cascade preview with multi-format export
A foreign key is a column (or set of columns) in one table that references the primary key of another table.
Example:
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE posts (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
title TEXT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);In this example:
-
posts.user_idis a foreign key - It references
users.id - Enforces referential integrity
Benefits:
- Data Integrity - Prevents orphaned records
- Relationship Enforcement - Maintains valid references
- Cascade Operations - Automatic cleanup of related data
- Documentation - Makes relationships explicit
Example Scenario:
If you delete a user, what happens to their posts?
- CASCADE: Posts are automatically deleted
- RESTRICT: Deletion blocked until posts removed
- SET NULL: Posts remain but user_id set to NULL
- NO ACTION: Same as RESTRICT
Tables that this table references (via its foreign keys).
Example:
-- posts table has outbound dependency to users
CREATE TABLE posts (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);Visualization:
posts β users
(posts references users)
Meaning:
-
postsdepends onusers - Each post belongs to a user
- Deleting a user may affect posts (depending on ON DELETE)
Tables that reference this table (have foreign keys pointing to it).
Example:
-- users table has inbound dependency from posts
-- (posts.user_id references users.id)Visualization:
users β posts
(users is referenced by posts)
Meaning:
- Other tables depend on
users - Deleting a user may cascade to
posts - Must consider impact on dependent tables
Behavior: Automatically delete dependent rows when parent is deleted.
Example:
CREATE TABLE comments (
id INTEGER PRIMARY KEY,
post_id INTEGER NOT NULL,
content TEXT,
FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE
);Result:
Delete post (id=1) β All comments with post_id=1 are automatically deleted
Use Cases:
- Comments when post is deleted
- Order items when order is deleted
- Related data that has no meaning without parent
Warning:
β οΈ CASCADE deletions are permanent!
Deleting will cascade to 152 rows in 'comments'
Behavior: Prevent deletion if dependent rows exist.
Example:
CREATE TABLE invoices (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT
);Result:
Delete user (id=1) β Error: "Cannot delete, invoices exist"
Must delete invoices first, then user
Use Cases:
- Financial records (invoices, payments)
- Audit logs
- Critical data that should never cascade
- Data requiring explicit handling
Warning:
β οΈ RESTRICT constraint prevents deletion
Table 'invoices' will block deletion of user
Behavior: Set foreign key column to NULL when parent is deleted.
Example:
CREATE TABLE posts (
id INTEGER PRIMARY KEY,
user_id INTEGER, -- Nullable
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
);Result:
Delete user (id=1) β All posts with user_id=1 have user_id set to NULL
Posts remain, but no longer associated with a user
Use Cases:
- Optional relationships
- Historical data (keep record but remove reference)
- Soft deletions
- Data that can exist independently
Warning:
β οΈ SET NULL will orphan 47 posts
Posts will remain but lose user reference
Behavior: Similar to RESTRICT (depends on SQLite version).
In SQLite:
- Behaves like RESTRICT in most cases
- Checks constraint at end of statement
- Usually prevents deletion
Example:
CREATE TABLE posts (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE NO ACTION
);Result:
Usually blocks deletion like RESTRICT
When attempting to delete a table or row:
Single Table Delete:
ββββββββββββββββββββββββββββββββββββββββββββ
β Delete Table: users β
ββββββββββββββββββββββββββββββββββββββββββββ€
β β οΈ This table has dependencies β
β β
β Outbound Dependencies: β
β None β
β β
β Inbound Dependencies: β
β β’ posts (CASCADE) - 152 rows β
β β’ comments (CASCADE) - 47 rows β
β β’ sessions (CASCADE) - 3 rows β
β β
β Total Impact: 202 rows will be deleted β
β β
β β‘ I understand the impact β
β β
β [Cancel] [Delete Table] β
ββββββββββββββββββββββββββββββββββββββββββββ
Bulk Table Delete:
ββββββββββββββββββββββββββββββββββββββββββββ
β Delete 3 Tables β
ββββββββββββββββββββββββββββββββββββββββββββ€
β βΌ users (2 dependencies) β
β Inbound: posts (152 rows CASCADE) β
β Inbound: comments (47 rows CASCADE) β
β β
β βΌ posts (1 dependency) β
β Outbound: users (references user_id) β
β β
β βΆ tags (0 dependencies) β
β β
β β‘ I understand the dependencies β
β β
β [Cancel] [Delete Tables] β
ββββββββββββββββββββββββββββββββββββββββββββ
Each dependency shows:
β οΈ Table: posts
Relationship: Inbound (this table is referenced)
Column: user_id β users.id
ON DELETE: CASCADE
Impact: 152 rows will be deleted
Severity: High (>100 rows)
Color Coding:
- π΄ Red - RESTRICT (blocks deletion)
- π‘ Yellow - CASCADE (high impact >50 rows)
- π΅ Blue - SET NULL (data modified)
- βͺ Gray - NO ACTION or low impact
Step 1: Query Foreign Keys
PRAGMA foreign_key_list(table_name);Returns:
id | seq | table | from | to | on_update | on_delete
0 | 0 | users | user_id | id | NO ACTION | CASCADE
Step 2: Identify Relationships
- Outbound: Foreign keys in this table
- Inbound: Foreign keys in other tables pointing here
Step 3: Count Affected Rows
SELECT COUNT(*)
FROM dependent_table
WHERE foreign_key_column = target_value;Step 4: Determine Severity
- High: >100 rows, RESTRICT, or deep cascades
- Medium: 20-100 rows
- Low: <20 rows
Step 5: Display Results
- Show in delete dialog
- Color-code by severity
- Require confirmation if dependencies exist
Target: Delete user (id = 5)
Query 1: Find outbound dependencies
PRAGMA foreign_key_list('users');
-- Result: None (users doesn't reference other tables)Query 2: Find inbound dependencies
-- Check all tables for foreign keys to users
PRAGMA foreign_key_list('posts');
PRAGMA foreign_key_list('comments');
PRAGMA foreign_key_list('sessions');Query 3: Count affected rows
SELECT COUNT(*) FROM posts WHERE user_id = 5; -- 152
SELECT COUNT(*) FROM comments WHERE user_id = 5; -- 47
SELECT COUNT(*) FROM sessions WHERE user_id = 5; -- 3Result Display:
Total Impact: 202 rows across 3 tables
- posts: 152 rows (CASCADE)
- comments: 47 rows (CASCADE)
- sessions: 3 rows (CASCADE)
For Row Deletion:
SELECT COUNT(*)
FROM dependent_table
WHERE foreign_key_column = ?;For Table Deletion:
SELECT COUNT(*)
FROM dependent_table;Accurate When:
- Simple foreign key relationships
- No triggers modifying behavior
- Foreign keys enabled
May Differ When:
- Triggers perform additional operations
- Complex cascade chains
- Concurrent modifications
Note: Counts are estimates based on current data. Use Cascade Impact Simulator for detailed analysis.
Confirmation checkbox appears when:
- β Any dependencies exist
- β CASCADE operations will occur
- β SET NULL operations will affect data
- β RESTRICT constraints prevent deletion
Checkbox Text:
β‘ I understand that deleting this table/row will affect dependent tables
Prevents:
- Accidental data loss
- Unintended cascade deletions
- Surprise RESTRICT errors
- Data integrity issues
Ensures:
- User awareness of impact
- Deliberate action
- Informed decision
- Audit trail (user acknowledged)
Before Confirmation:
[Cancel] [Delete Table] (disabled, grayed out)
After Confirmation:
[Cancel] [Delete Table] (enabled, clickable)
Schema:
CREATE TABLE users (id PRIMARY KEY, name TEXT);
CREATE TABLE posts (id PRIMARY KEY, user_id INTEGER,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE);
CREATE TABLE comments (id PRIMARY KEY, post_id INTEGER, user_id INTEGER,
FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE);Delete User:
Outbound: None
Inbound:
- posts β CASCADE (152 rows deleted)
- comments β CASCADE (89 rows deleted)
Total Impact: 241 rows
Delete Post:
Outbound:
- users (referenced, not affected by post deletion)
Inbound:
- comments β CASCADE (47 rows deleted)
Total Impact: 48 rows (post + comments)
Schema:
CREATE TABLE customers (id PRIMARY KEY);
CREATE TABLE orders (id PRIMARY KEY, customer_id INTEGER,
FOREIGN KEY (customer_id) REFERENCES customers(id) ON DELETE RESTRICT);
CREATE TABLE order_items (id PRIMARY KEY, order_id INTEGER,
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE);Delete Customer:
Inbound:
- orders β RESTRICT (prevents deletion)
β Cannot delete customer with orders
Must delete orders first (or change to CASCADE/SET NULL)
Delete Order:
Outbound:
- customers (referenced, not affected)
Inbound:
- order_items β CASCADE (5 rows deleted)
Total Impact: 6 rows (order + items)
Schema:
CREATE TABLE users (id PRIMARY KEY);
CREATE TABLE profiles (id PRIMARY KEY, user_id INTEGER,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE);
CREATE TABLE preferences (id PRIMARY KEY, user_id INTEGER,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL);Delete User:
Inbound:
- profiles β CASCADE (1 row deleted)
- preferences β SET NULL (1 row modified, user_id = NULL)
Total Impact: 1 deletion, 1 modification
Choose appropriate ON DELETE:
- CASCADE: For dependent data (comments, items)
- RESTRICT: For important records (invoices, audit logs)
- SET NULL: For optional relationships (author of post)
- NO ACTION: When uncertain (can change later)
In schema creation:
-- User posts: CASCADE because posts have no meaning without user
CREATE TABLE posts (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);
-- User invoices: RESTRICT to prevent accidental deletion of financial data
CREATE TABLE invoices (
id INTEGER PRIMARY KEY,
user_id INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT
);Before deleting:
- Check dependency viewer
- Understand cascade impact
- Consider using Cascade Impact Simulator
- Export data if needed
- Proceed with confirmation
Workflow:
- Create test data in development
- Test deletion scenarios
- Verify CASCADE behavior
- Adjust foreign keys if needed
- Deploy to production
When RESTRICT blocks deletion:
Option 1: Delete dependencies first
DELETE FROM orders WHERE customer_id = 5;
DELETE FROM customers WHERE id = 5;Option 2: Change foreign key
-- Recreate table with CASCADE instead of RESTRICTOption 3: Keep the constraint
Maybe RESTRICT is correct - don't delete parent data!
Cause: Foreign keys not enabled in SQLite.
Check:
PRAGMA foreign_keys;
-- Should return 1 (enabled)Enable:
PRAGMA foreign_keys = ON;Note: D1 enables foreign keys by default.
Cause: Data changed between analysis and display.
Solution:
- Refresh the dialog
- Re-run dependency analysis
- Check for concurrent modifications
Cause: Foreign keys not enforced.
Solution:
-- Verify foreign keys enabled
PRAGMA foreign_keys;
-- Check foreign key definition
PRAGMA foreign_key_list(table_name);Scenario:
-- users references profiles
CREATE TABLE users (
profile_id INTEGER,
FOREIGN KEY (profile_id) REFERENCES profiles(id)
);
-- profiles references users
CREATE TABLE profiles (
user_id INTEGER,
FOREIGN KEY (user_id) REFERENCES users(id)
);Result: Both tables depend on each other.
Solution:
- Review design
- Consider breaking circular reference
- Use triggers if necessary
- Document intentional circles
GET /api/tables/:dbId/dependencies?tables=users,postsResponse:
{
"users": {
"outbound": [],
"inbound": [
{
"table": "posts",
"column": "user_id",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"rowCount": 152
}
]
}
}See API Reference for complete documentation.
- Composite foreign keys supported
- Deferred constraints not available in D1
- ON UPDATE CASCADE not widely used
Dependencies to/from views are not analyzed.
Workaround: Check view definitions manually.
If your app enforces relationships in code (not database), the dependency viewer won't detect them.
Workaround: Document application-level relationships separately.
From the dependencies viewer, you can quickly navigate to any referenced or referencing table by clicking the table name. The navigation maintains a breadcrumb trail and applies relevant filters automatically.
When viewing dependencies before a table deletion:
- Click a referenced table name - Navigate to that table
- Breadcrumb updates - Shows your navigation path
- Context preserved - You can return to the delete dialog
- Explore relationships - Verify data before committing to deletion
Verify Dependencies Before Deletion
Before deleting a table:
- View the dependency analysis
- Click an inbound dependency table name
- See which records reference your table
- Decide if it's safe to delete
Explore Relationship Chains
Starting from one table:
- View its dependencies
- Navigate to a referenced table
- View that table's dependencies
- Continue exploring the relationship graph
Data Auditing
When investigating data integrity:
- Start at a suspicious table
- Click through dependencies to find the root cause
- Use breadcrumbs to trace back your investigation path
For comprehensive navigation features, see the Foreign Key Navigation guide.
- Foreign Key Navigation - Navigate between tables via FK values
- Foreign Key Visualizer - Visual constraint management and interactive graph
- Cascade Impact Simulator - Detailed cascade analysis
- Table Operations - Delete operations
- Query Console - Create foreign keys
- Database Management - Schema management
Need Help? See Troubleshooting or open an issue.
- Database Management
- R2 Backup Restore
- Scheduled Backups
- Table Operations
- Query Console
- Schema Designer
- Column Management
- Bulk Operations
- Job History
- Time Travel
- Read Replication
- Undo Rollback
- Foreign Key Visualizer
- ER Diagram
- Foreign Key Dependencies
- Foreign Key Navigation
- Circular Dependency Detector
- Cascade Impact Simulator
- AI Search
- FTS5 Full Text Search
- Cross Database Search
- Index Analyzer
- Database Comparison
- Database Optimization