The "110%" Database Migration Suite for Convex
✨ Official Landing Page (Deployable to Cloudflare Pages)
Auto-converts SQL constraints to Validators, Auto-suggests Indexes, and Generates type-safe Mutations/Queries.
AQM = Actions, Queries, Mutations - the building blocks of Convex
SunSetter is more than just a data mover. It understands your SQL schema better than you do.
Most tools drop your SQL constraints. SunSetter parses them into Convex Validators.
- SQL:
CHECK (age >= 18 AND age <= 120) - Convex:
v.number().gte(18).lte(120)
NoSQL indexing is hard. SunSetter analyzes your foreign keys and query patterns to suggest high-impact indexes automatically.
- Streaming: O(1) memory usage via cursor-based pagination.
- Parallelism: Concurrent table processing with dependency graph resolution.
- Safety: Dry-run mode and rollback capabilities.
- PostgreSQL - Full support with multi-schema introspection & Enum auto-detection
- MySQL / MariaDB - Complete type mapping and streaming
- SQLite - File-based database migration
- SQL Server (MSSQL) - Enterprise database support
- Convex Schema - Type-safe schema with validators
- Queries - Paginated list, getById, search, filtering
- Mutations - Create, update, remove, batch operations
- Actions - External API sync, document processing
- HTTP Actions - REST API endpoints with auth stubs
- TypeScript Types - Full type definitions
- Streaming - Memory-efficient cursor-based pagination
- Parallel Migration - Concurrent table processing with dependency awareness
- Checkpointing - Resume interrupted migrations
- Rollback - Delete migrated documents if needed
- Dry Run - Preview changes without writing
- Interactive Wizard - Guided setup experience
- Visual Progress - Real-time progress bars per table
- Dashboard - Live migration statistics
- Slack Notifications - Real-time migration alerts to Slack
- PII Data Masking - GDPR-compliant data anonymization
- Post-Migration Verification - Validate row counts after migration
- React Hooks Generation - Type-safe React hooks for Convex
- Connection Validation - Helpful errors with cloud provider examples
- Claude Code - Use as an MCP server in Claude Code CLI
- Claude Desktop - Integrate with Claude Desktop app
- IDE Extensions - Works with VSCode Claude extensions
npm install -g @the-fbf/sunsetter-aqmOr run directly:
npx @the-fbf/sunsetter-aqmsunsetter wizardPostgreSQL:
sunsetter migrate -c "postgresql://user:pass@localhost:5432/mydb" \
--convex-url https://your-app.convex.cloud \
--convex-deploy-key your-deploy-keyMySQL:
sunsetter migrate -c "mysql://user:pass@localhost:3306/mydb"SQLite:
sunsetter migrate -c "sqlite:///path/to/database.db"SQL Server:
sunsetter migrate -c "mssql://user:pass@localhost:1433/mydb"| Command | Description |
|---|---|
wizard |
Interactive setup wizard |
migrate |
Run database migration |
generate |
Generate Convex code only (no data) |
introspect |
Inspect database schema |
preflight |
Pre-migration validation and estimates |
export-seed |
Export seed data for testing |
init |
Create sample configuration file |
validate-config |
Validate configuration file |
doctor |
Check system dependencies |
Create a .sunsetterrc or .sunsetterrc.json in your project:
{
"connection": {
"string": "postgresql://localhost/mydb"
},
"convex": {
"deploymentUrl": "https://your-app.convex.cloud"
},
"migration": {
"batchSize": 100,
"parallel": true,
"maxParallelTables": 4
},
"generation": {
"queries": true,
"mutations": true,
"actions": true,
"httpActions": true
},
"output": {
"format": "pretty"
}
}Generate a sample config:
sunsetter init# Schema only - generate Convex code
sunsetter migrate -m schema-only
# Schema and data - full migration
sunsetter migrate -m schema-and-data
# Data only - migrate to existing schema
sunsetter migrate -m data-onlysunsetter --help
Global Options:
-v, --version Show version number
--help Show help
--help-full Show detailed help with examples
--config <path> Path to config file
--json Output in JSON format (for CI/CD)
--quiet Suppress non-essential output
--verbose Show detailed output
Migration Options:
-c, --connection <string> Database connection string
-t, --tables <tables> Specific tables to migrate (comma-separated)
-m, --mode <mode> Migration mode (schema-only|data-only|schema-and-data)
--db-type <type> Database type (postgresql|mysql|sqlite|mssql)
--convex-url <url> Convex deployment URL
--convex-deploy-key <key> Convex deploy key
--batch-size <number> Rows per batch (default: 100)
--parallel Enable parallel table migration
--dry-run Preview without making changes
--resume Resume from checkpoint
--rollback Rollback previous migration
Enhancement Options:
--slack-webhook <url> Slack webhook for migration notifications
--mask-pii Enable PII data masking during migration
--verify Run post-migration verification
--react-hooks Generate React hooks for Convex functions
--hooks-output <dir> Output directory for hooks (default: ./src/hooks)For CI/CD pipelines, use --json for machine-readable output:
sunsetter migrate -c "postgresql://..." --jsonOutput format:
{
"success": true,
"operation": "migrate",
"timestamp": "2024-01-15T10:30:00.000Z",
"durationMs": 12500,
"data": {
"tablesProcessed": 5,
"rowsMigrated": 10000,
"errors": 0
}
}DATABASE_URL=postgresql://user:pass@localhost:5432/mydb
CONVEX_URL=https://your-app.convex.cloud
CONVEX_DEPLOY_KEY=your-deploy-keyconvex/
├── schema.ts # Convex schema definition
├── users.ts # Table: queries + mutations
├── users.actions.ts # Table: actions (external APIs)
├── users.http.ts # Table: HTTP endpoints
├── _generated/
│ └── types.ts # TypeScript types
└── http.ts # HTTP router
| SQL Type | Convex Type |
|---|---|
INTEGER, BIGINT |
v.int64() |
REAL, FLOAT, DECIMAL |
v.float64() |
VARCHAR, TEXT |
v.string() |
BOOLEAN |
v.boolean() |
TIMESTAMP, DATE |
v.int64() (Unix ms) |
JSON, JSONB |
v.any() |
UUID |
v.string() |
ARRAY |
v.array() |
| Foreign Key | v.id("referenced_table") |
SunSetter can run as an MCP (Model Context Protocol) server, enabling AI assistants like Claude to directly introspect databases and run migrations.
sunsetter --mcpAdd to your Claude Code settings (~/.config/claude-code/settings.json):
{
"mcpServers": {
"sunsetter": {
"command": "npx",
"args": ["@the-fbf/sunsetter-aqm", "--mcp"],
"description": "Database to Convex migration tool"
}
}
}Add to your Claude Desktop config (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"sunsetter": {
"command": "npx",
"args": ["@the-fbf/sunsetter-aqm", "--mcp"]
}
}
}| Tool | Description |
|---|---|
connect |
Connect to a database |
introspect_schema |
Introspect database schema |
list_tables |
List all tables |
get_table_info |
Get detailed table information |
preview_migration |
Preview migration plan |
generate_schema |
Generate Convex schema |
generate_queries |
Generate query functions |
generate_mutations |
Generate mutation functions |
run_migration |
Execute migration |
get_migration_status |
Check migration progress |
rollback_migration |
Rollback migration |
disconnect |
Close database connection |
schema://current- Current database schemamigration://status- Migration statusconvex://generated- Generated Convex codeconfig://current- Current configuration
plan-migration- Generate a migration plananalyze-schema- Analyze database schema for issuesoptimize-migration- Get optimization suggestions
Get real-time migration updates in Slack:
sunsetter migrate -c "postgresql://..." \
--slack-webhook "https://hooks.slack.com/services/XXX/YYY/ZZZ"Notifications include:
- Migration start (tables, estimated rows)
- Migration complete (duration, rows migrated, failures)
- Migration failure (error details, failed table)
Anonymize sensitive data during migration for GDPR/HIPAA compliance:
sunsetter migrate -c "postgresql://..." --mask-piiConfigure masking rules in .sunsetterrc:
{
"dataMasking": {
"enabled": true,
"tables": [
{
"tableName": "users",
"fields": {
"email": "email",
"phone": "phone",
"name": "name",
"ssn": "redact"
}
}
]
}
}Masking strategies: hash, redact, email, phone, name
Verify data integrity after migration:
sunsetter migrate -c "postgresql://..." --verifyVerification checks:
- Row count comparison (source vs Convex)
- Per-table PASS/FAIL status
- Summary report with mismatches
Generate type-safe React hooks for your Convex functions:
sunsetter migrate -c "postgresql://..." \
--react-hooks \
--hooks-output ./src/hooksGenerated hooks per table:
useUsersList()- Paginated list queryuseUser(id)- Single document queryuseCreateUser()- Create mutationuseUpdateUser()- Update mutationuseRemoveUser()- Delete mutation
SunSetter exports utility functions for programmatic use:
// Import from utils subpath
import {
parseConnectionString,
validateConnectionString,
maskPassword,
escapeHtml,
buildConnectionString,
detectCloudProvider,
} from '@the-fbf/sunsetter-aqm/utils';
// Or import directly
import { parseConnectionString } from '@the-fbf/sunsetter-aqm/utils/connection-validator';
// Parse connection string
const parsed = parseConnectionString('postgresql://user:pass@localhost/db');
// => { type: 'postgresql', host: 'localhost', database: 'db', ... }
// Validate with helpful errors
const result = validateConnectionString(connectionString);
// => { valid: boolean, errors: [], warnings: [], suggestions: [] }
// Mask password for logging (safe for output)
const masked = maskPassword('postgresql://user:secret@host/db');
// => 'postgresql://user:***@host/db'
// Escape HTML for XSS prevention
const safe = escapeHtml('<script>alert("xss")</script>');
// => '<script>alert("xss")</script>'// Import from utils subpath
import {
fuzzyMatch,
suggestTableNames,
findBestMatch,
type FuzzyMatchResult,
} from '@the-fbf/sunsetter-aqm/utils';
// Or import directly
import { fuzzyMatch } from '@the-fbf/sunsetter-aqm/utils/fuzzy-match';
// Find matches with new combined API
const result: FuzzyMatchResult = fuzzyMatch('usres', ['users', 'orders'], 0.6);
// => {
// exact: null, // FuzzyMatch | null - exact match if found
// fuzzy: [{ value: 'users', score: 0.8, distance: 2 }] // sorted by score
// }
// With exact match - returns immediately (early termination)
const result2 = fuzzyMatch('users', ['users', 'orders']);
// => { exact: { value: 'users', score: 1, distance: 0 }, fuzzy: [] }
// Suggest corrections for table names
const suggestion = suggestTableNames('usres', ['users', 'orders', 'products']);
// => { exists: false, exactMatch: null, suggestions: [...] }For more detailed guides, see:
- QUICK_REFERENCE_110.md - Quick API reference card
- MIGRATION_GUIDE_110.md - Step-by-step migration workflow
- ENHANCEMENTS_110_PERCENT.md - Detailed feature documentation
- ARCHITECTURE_110.md - System architecture deep dive
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Source DB │────▶│ SunSetter AQM+ │────▶│ Convex │
│ (PG/MySQL/etc) │ │ │ │ │
└─────────────────┘ │ - Introspect │ │ - Schema │
│ - Transform │ │ - Documents │
│ - Stream │ │ - Functions │
└──────────────────┘ └─────────────────┘
Check your system:
sunsetter doctorRequirements:
- Node.js 18+
- npm or yarn
- Database client (optional, for validation)
Migrations are easy. Architecture decisions are hard.
This tool handles the mechanical work, but you might want expert help with:
- Schema design for Convex (NoSQL is different from SQL)
- Index optimization for your query patterns
- Handling edge cases and complex data relationships
- Production migration planning and rollback strategies
Consulting available → heyoub.dev
Contributions welcome! Please read CONTRIBUTING.md first.
GPL-3.0-or-later - see LICENSE
Built by Heyoub for the Convex community