-
Notifications
You must be signed in to change notification settings - Fork 2
Table Operations
Complete guide to managing tables in D1 databases with D1 Database Manager.
D1 Manager provides comprehensive table management:
- 📋 Browse tables with grid/list view toggle, search, and row search filter
- 👀 View table schemas, indexes, row counts, and status badges (STRICT, FTS5)
- ➕ Create tables (visual designer or SQL)
- ✏️ Rename tables
- 📋 Clone tables (structure + data + indexes)
- 📤 Export tables (SQL/CSV/JSON) and import data (CSV/JSON/SQL) with duplicate handling and auto-add missing columns
- 🛟 Table-level R2 Backup/Restore (when R2 is configured) plus undo snapshots for destructive operations
- 🗑️ Delete tables with dependency analysis and cascade impact simulation
- 📦 Bulk operations (clone, export, delete multiple tables)
- 🔧 Column management (add, modify, rename, delete) including STRICT mode conversions and generated columns
Navigate to a database to see all its tables.
┌─────────────────────────────────┐
│ [✓] 📊 users │
│ │
│ Columns: 5 • Rows: 1,234 │
│ Type: table • STRICT │
│ │
│ [Browse] [Schema] [Export] [⋮] │
│ [Backup] [Restore] [Color] │
└─────────────────────────────────┘
Card Information:
- Checkbox - For bulk operations
- Name - Table name
- Columns/Rows - Number of columns and row count (where available)
- Type - table, view, or virtual; STRICT/FTS5 badges where applicable
- Color tag - Optional color for quick visual grouping
Quick Actions:
- Browse - View table data
- Schema - View column definitions
- Export - Download as SQL/CSV
- Backup/Restore - Table-level R2 backup and restore (when R2 is configured)
- More Menu (⋮) - Rename, Clone, Delete, Convert (STRICT/FTS5), Import
Use the search bar to quickly find tables by name:
┌─────────────────────────────────────────────────┐
│ 🔍 Search tables... │
└─────────────────────────────────────────────────┘
Showing 3 of 12 tables matching "user"
Features:
- Instant filtering - Results update as you type
- Case-insensitive - "USERS", "users", and "Users" all match
- Partial matching - Search "user" matches "users", "user_logs", "admin_users", etc.
- Clear button - Click X to clear the search
- Row search - When browsing data, use the row search input to quickly filter visible rows client-side
Click "Browse" to view table contents:
┌──────┬──────────┬──────────────────┬─────────────┐
│ id │ name │ email │ created_at │
├──────┼──────────┼──────────────────┼─────────────┤
│ 1 │ Alice │ alice@email.com │ 2024-11-01 │
│ 2 │ Bob │ bob@email.com │ 2024-11-02 │
│ 3 │ Charlie │ charlie@email.com│ 2024-11-03 │
└──────┴──────────┴──────────────────┴─────────────┘
Showing 50 rows • Page 1 of 5 • [Previous] [Next]
Features:
- Pagination - 50 rows per page
- Sortable Columns - Click headers to sort
- Row search filter - Client-side text search across visible columns
- Navigation - Previous/Next page buttons
Click "Schema" to view column definitions:
┌─────────────────────────────────────────────────────┐
│ Table: users │
├─────────────────────────────────────────────────────┤
│ Column Type Constraints │
├─────────────────────────────────────────────────────┤
│ 🔑 id INTEGER PRIMARY KEY, NOT NULL │
│ name TEXT NOT NULL │
│ email TEXT UNIQUE, NOT NULL │
│ created_at DATETIME DEFAULT CURRENT_TIMESTAMP │
└─────────────────────────────────────────────────────┘
Column Information:
- Name - Column identifier
- Type - Data type (INTEGER, TEXT, REAL, BLOB, etc.)
- Constraints - PRIMARY KEY, UNIQUE, NOT NULL, DEFAULT
Key Indicators:
- 🔑 - Primary key column
⚠️ - NOT NULL constraint
Expand the indexes section to see:
┌─────────────────────────────────────────────────────┐
│ Indexes on users │
├─────────────────────────────────────────────────────┤
│ idx_users_email (email) - UNIQUE │
│ idx_users_created (created_at) │
└─────────────────────────────────────────────────────┘
The recommended way to create tables with a graphical interface.
Steps:
- Navigate to a database
- Click "Create Table"
- Enter table name
- Add columns using the visual builder
- Review SQL preview
- Click "Create"
Add Column Interface:
┌─────────────────────────────────────────┐
│ Column 1 │
├─────────────────────────────────────────┤
│ Name: [username ] │
│ Type: [▼ TEXT ] │
│ □ NOT NULL │
│ □ PRIMARY KEY │
│ Default: [ ] │
│ │
│ [+ Add Column] [Remove] │
└─────────────────────────────────────────┘
Column Types:
-
TEXT- String data -
INTEGER- Whole numbers -
REAL- Decimal numbers -
BLOB- Binary data -
NUMERIC- Numeric data (flexible)
Constraints:
- NOT NULL - Value required
- PRIMARY KEY - Unique identifier
- DEFAULT - Default value if not specified
SQL Preview:
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);Validation:
- Table name required
- At least one column required
- Column names must be unique
- PRIMARY KEY conflicts prevented
Use the Query Console to create tables with SQL:
CREATE TABLE products (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
description TEXT,
price REAL NOT NULL DEFAULT 0.0,
stock INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);Benefits of SQL method:
- More control
- Complex constraints (FOREIGN KEY, CHECK)
- Trigger creation
- View creation
POST /api/tables/:dbId/create
Content-Type: application/json
{
"tableName": "users",
"columns": [
{
"name": "id",
"type": "INTEGER",
"primaryKey": true,
"notNull": true
},
{
"name": "name",
"type": "TEXT",
"notNull": true
}
]
}Rename tables with validation and dependency checking.
Steps:
- Click "Rename" button on table card
- Enter new name
- Review warnings
- Click "Rename Table"
Validation:
- New name must be unique
- Cannot rename system tables
- Name follows SQLite naming rules
SQL Operation:
ALTER TABLE old_name RENAME TO new_name;Fast Operation:
- Instant rename (no data copy)
- Preserves all indexes
- Preserves foreign keys
- Preserves triggers
PATCH /api/tables/:dbId/:tableName/rename
Content-Type: application/json
{
"newName": "customers"
}Create exact copies of tables including structure, data, and indexes.
Steps:
- Click "Clone" button on table card
- Enter new table name
- Review what will be copied
- Click "Clone Table"
What Gets Cloned:
- ✅ Table structure (columns, types, constraints)
- ✅ All data rows
- ✅ All indexes
- ❌ Foreign key references (new table is independent)
- ❌ Triggers (SQLite limitation)
Clone Process:
-- 1. Copy structure
CREATE TABLE users_copy AS SELECT * FROM users;
-- 2. Recreate indexes
CREATE INDEX idx_users_copy_email ON users_copy(email);
-- 3. Verify row count
SELECT COUNT(*) FROM users_copy;Use Cases:
- Testing - Test changes on copy
- Backup - Quick table backup
- Versioning - Keep historical snapshots
- Development - Work on copy, not production
Clone multiple tables at once:
- Select tables using checkboxes
- Click "Clone Selected"
- Review suggested names
- Modify names if needed
- Click "Clone Tables"
Naming Suggestions:
users → users_copy
posts → posts_copy
comments → comments_copy
POST /api/tables/:dbId/:tableName/clone
Content-Type: application/json
{
"newTableName": "users_copy"
}Export tables as SQL dumps or CSV files.
Steps:
- Click "Export" button on table card
- Choose format:
- SQL - Complete table dump with CREATE and INSERT
- CSV - Data only in CSV format
- File downloads automatically
SQL Export Format:
-- users.sql
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE
);
INSERT INTO users (id, name, email) VALUES
(1, 'Alice', 'alice@email.com'),
(2, 'Bob', 'bob@email.com');
CREATE INDEX idx_users_email ON users(email);CSV Export Format:
id,name,email
1,Alice,alice@email.com
2,Bob,bob@email.comExport multiple tables in a ZIP archive:
- Select tables using checkboxes
- Click "Export Selected"
- Choose format (SQL or CSV)
- Click "Export"
- Download ZIP file
ZIP Structure (SQL):
tables-export.zip
├── users.sql
├── posts.sql
└── comments.sql
ZIP Structure (CSV):
tables-export.zip
├── users.csv
├── posts.csv
└── comments.csv
Single Table:
GET /api/tables/:dbId/:tableName/export?format=sql
GET /api/tables/:dbId/:tableName/export?format=csvBulk Export:
POST /api/tables/:dbId/bulk-export
Content-Type: application/json
{
"tableNames": ["users", "posts", "comments"],
"format": "sql"
}Delete tables with foreign key dependency analysis, cascade impact simulation, and automatic undo snapshots/R2 backups.
Steps:
- Click "Delete" from more menu (⋮)
- Review dependency analysis
- Optional: Click "Simulate Cascade Impact" for detailed visualization
- Read warnings about cascade impacts
- Check confirmation checkbox (if dependencies exist)
- Click "Delete Table"
Undo/Rollback Support:
- ✅ Automatic undo snapshot - Table schema, indexes, and data are captured before deletion
- ✅ R2 backup option (when R2 is configured) - Create a cloud backup before delete; table backups appear in the Backup & Restore hub
- ✅ Restore capability - Click Backup & Restore in the header to restore undo snapshots or R2 backups
- ✅ History - Undo history per database and R2 backup history (including orphaned backups)
See Undo Rollback for complete documentation.
For comprehensive deletion analysis, use the Cascade Impact Simulator button:
- Interactive Graph - Visual representation of all cascade paths
- Row Count Analysis - Exact counts of affected rows at each level
- Warning System - Severity-based alerts for high-impact operations
- Export Options - Generate CSV, JSON, Text, or PDF reports
See Cascade Impact Simulator for complete documentation.
When to Use:
- Deleting tables with complex foreign key relationships
- Need detailed impact analysis before proceeding
- Documenting deletion operations for compliance
- Understanding cascade depth and circular dependencies
Before deletion, D1 Manager shows:
Outbound Dependencies:
⚠️ Table users references roles (role_id → id)
ON DELETE: CASCADE
Inbound Dependencies:
⚠️ Table posts references users (user_id → id)
ON DELETE: CASCADE
Affected: 152 rows will be deleted
Dependency Details:
- Referenced Table - Table being referenced
- Column - Foreign key column
- ON DELETE Behavior - CASCADE, RESTRICT, SET NULL, NO ACTION
- Row Count - Estimated rows affected
See Foreign Key Dependencies for more details.
If dependencies exist:
┌─────────────────────────────────────────────┐
│ ⚠️ Warning: This table has dependencies │
├─────────────────────────────────────────────┤
│ Deleting will affect: │
│ • posts (152 rows will be CASCADE deleted) │
│ • comments (47 rows will be CASCADE deleted)│
│ │
│ □ I understand that deleting this table │
│ will affect dependent tables │
│ │
│ [Cancel] [Delete Table] (disabled) │
└─────────────────────────────────────────────┘
Delete multiple tables with dependency analysis:
Steps:
- Select tables using checkboxes
- Click "Delete Selected"
- Review dependencies for each table
- Check confirmation boxes
- Click "Delete Tables"
Progress Tracking:
Analyzing dependencies...
Deleting table 1 of 3: users...
Deleting table 2 of 3: posts...
Deleting table 3 of 3: comments...
Complete: 3 tables deleted
Dependency Accordion:
┌─────────────────────────────────────────┐
│ ▼ users (2 dependencies) │
├─────────────────────────────────────────┤
│ Inbound: posts (152 rows CASCADE) │
│ Inbound: comments (47 rows CASCADE) │
└─────────────────────────────────────────┘
│ ▼ posts (1 dependency) │
├─────────────────────────────────────────┤
│ Outbound: users (references user_id) │
└─────────────────────────────────────────┘
Single Delete:
DELETE /api/tables/:dbId/:tableNameGet Dependencies:
GET /api/tables/:dbId/dependencies?tables=users,postsResponse:
{
"users": {
"outbound": [],
"inbound": [
{
"table": "posts",
"column": "user_id",
"onDelete": "CASCADE",
"rowCount": 152
}
]
}
}Add, modify, rename, and delete columns from existing tables.
See Column Management for detailed documentation.
Quick Reference:
ALTER TABLE users ADD COLUMN phone TEXT;ALTER TABLE users RENAME COLUMN name TO full_name;Uses table recreation:
-- Change column type or constraints
-- Involves copying data to new tableALTER TABLE users DROP COLUMN phone;Shown at bottom of table view:
Showing 50 of 1,234 rows
View in database info:
- Total database size
- Table count
- Largest tables
View all indexes on a table:
┌─────────────────────────────────────────┐
│ Indexes │
├─────────────────────────────────────────┤
│ sqlite_autoindex_users_1 (email) UNIQUE│
│ idx_users_created (created_at) │
│ idx_users_name (name) │
└─────────────────────────────────────────┘
Use descriptive, consistent names:
✅ users
✅ blog_posts
✅ user_sessions
✅ product_categories
Avoid:
❌ tbl_users (redundant prefix)
❌ Users (inconsistent casing)
❌ user-data (hyphens in table names)
Good Structure:
CREATE TABLE orders (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
total REAL NOT NULL DEFAULT 0.0,
status TEXT NOT NULL DEFAULT 'pending',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);Key Principles:
- Always have a PRIMARY KEY
- Use AUTOINCREMENT for auto-generated IDs
- Use NOT NULL for required fields
- Provide sensible DEFAULT values
- Add foreign keys for referential integrity
Create indexes for:
- Foreign keys - Always index FK columns
- Search columns - Columns in WHERE clauses
- Sort columns - Columns in ORDER BY
- Join columns - Columns used in JOINs
CREATE INDEX idx_posts_user ON posts(user_id);
CREATE INDEX idx_posts_created ON posts(created_at);
CREATE INDEX idx_posts_status ON posts(status);Always backup before:
- Dropping columns
- Modifying column types
- Deleting tables with dependencies
- Bulk operations
Cause: Table name conflicts with existing table
Solution:
-- Check existing tables
SELECT name FROM sqlite_master WHERE type='table';
-- Use different name or drop existing table first
DROP TABLE IF EXISTS old_table;Cause: Trying to drop the only column
Solution:
- Tables must have at least one column
- Add a new column first, then drop the old one
Cause: Trying to delete/modify row that's referenced
Solution:
-- Check foreign key constraints
PRAGMA foreign_key_list(table_name);
-- Options:
-- 1. Delete dependent rows first
-- 2. Set ON DELETE CASCADE
-- 3. Temporarily disable FK checks (not recommended)Cause: Table too large for export
Solution:
- Use Wrangler CLI for large tables
- Export in batches using SQL queries with LIMIT/OFFSET
wrangler d1 execute my-db --remote --command="SELECT * FROM large_table LIMIT 10000 OFFSET 0"GET /api/tables/:dbId/listGET /api/tables/:dbId/schema/:tableNameGET /api/tables/:dbId/data/:tableName?limit=50&offset=0GET /api/tables/:dbId/indexes/:tableNamePOST /api/tables/:dbId/createPATCH /api/tables/:dbId/:tableName/renamePOST /api/tables/:dbId/:tableName/cloneGET /api/tables/:dbId/:tableName/export?format=sql|csvDELETE /api/tables/:dbId/:tableNameGET /api/tables/:dbId/dependencies?tables=table1,table2When viewing table data, columns that are foreign keys are automatically detected and displayed as clickable links. Clicking a foreign key value navigates to the referenced table with an automatic filter applied to show only related records.
🔗 Clickable FK Values with Visual Indicators
Foreign key columns display with:
- Link icon (🔗) indicating the column is a foreign key
- Blue border and primary color styling
- Hover tooltips showing the referenced table (e.g., "References customers.id")
- Click to navigate to the referenced table
🍞 Breadcrumb Trail Showing Navigation Path
The breadcrumb navigation appears when you navigate via foreign keys:
Database > orders > customers > addresses
- Click any table name to jump back to that point
- Shows last 5 tables (older tables indicated with "...")
- Current table is highlighted and non-clickable
🔍 Auto-Filtering on Referenced Column
When navigating via FK:
- Target table opens automatically
- Filter applied to the referenced column matching your clicked value
- Only relevant related records are shown
- Filter bar displays with the auto-applied filter
⌨️ Keyboard Shortcut: Alt+Left to Go Back
Press Alt+Left Arrow to navigate back through your table history.
Scenario: View an order and explore its related customer
- Browse
orderstable - Click
customer_id = 42(FK value appears as blue link with icon) - Automatically navigates to
customerstable - Auto-filters to
WHERE id = 42 - Breadcrumb shows:
Database > orders > customers - Click "orders" in breadcrumb or press Alt+Left to return
- NULL Values: NULL foreign keys are not clickable and display as gray text
- Self-Referential FKs: Works correctly (e.g., employees.manager_id → employees.id)
- Composite FKs: Each column clickable individually
- No FK Constraints: If table has no foreign keys defined, all values display normally
- Use breadcrumbs to quickly jump to any previous table instead of clicking back multiple times
- Combine with filters: FK navigation adds an initial filter, but you can add more filters to narrow results
- Clear FK filter: After navigating, click "Clear All" in the filter bar to see the entire target table
- Watch the indicator: Table subtitle shows "• Navigated from FK" when in FK navigation mode
For comprehensive details, see the Foreign Key Navigation guide.
- Foreign Key Navigation - Complete guide to FK navigation
- Column Management - Manage table columns
- Foreign Key Dependencies - Understand relationships
- Schema Designer - Visual table creation
- Query Console - Execute SQL queries
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