Migrate your SQL
database to Convex
SunSetter reads your schema — tables, constraints, enums, foreign keys — and generates a complete Convex backend. Schema, queries, mutations, actions, crons, auth, and React hooks from one command.
npx @heyoub/sunsetter-aqm wizard
What it does
Most migration tools move your data and drop everything else. SunSetter carries over your schema logic too.
Constraint Translation
SQL CHECK constraints are parsed and converted to Convex validators. CHECK (age >= 18 AND age <= 120) becomes v.number().gte(18).lte(120).
Index Suggestions
Analyzes your foreign keys and column patterns to suggest Convex indexes with priority levels and copy-paste-ready code.
Full Code Generation
Generates schema.ts, queries, mutations, actions, HTTP endpoints, TypeScript interfaces, React hooks, and cron jobs for every table.
Component Config
Detects write-heavy tables and generates convex.config.ts with rate limiter, aggregate, and migrations components pre-wired.
Cron Scaffolding
Generates crons.ts with cleanup jobs for tables that have expires_at, deleted_at, or stuck-status patterns — using internalMutation.
Auth Scaffolding
Detects a users table with email + password columns and generates Convex Auth setup (auth.ts, auth.config.ts) with the Password provider.
File Storage Mapping
BYTEA, BLOB, and binary columns are mapped to v.id("_storage") with generated upload/download action stubs using Convex file storage.
PostgreSQL Deep Support
Auto-detects pg_enum types, handles partitioned tables and materialized views, and maps extension types like ltree and hstore.
Streaming Migration
Cursor-based pagination keeps memory constant regardless of table size. Supports parallel table migration, checkpointing, dry-run, and rollback.
What you get
Point SunSetter at a SQL database. It writes your Convex project structure.
export default defineSchema({
users: defineTable({
name: v.string(),
email: v.string(),
age: v.number().gte(18).lte(120),
role: v.union(
v.literal("admin"),
v.literal("editor"),
v.literal("viewer")
),
avatarId: v.optional(v.id("_storage")),
orgId: v.id("organizations"),
})
.index("by_email", ["email"])
.index("by_org", ["orgId"])
.searchIndex("search_name", {
searchField: "name",
}),
});
import { cronJobs } from "convex/server";
import { internalMutation } from "./_generated/server";
import { internal } from "./_generated/api";
const crons = cronJobs();
crons.daily(
"Purge soft-deleted users",
{ hourUTC: 3, minuteUTC: 0 },
internal.crons.purgeDeletedUsers
);
export default crons;
import { defineApp } from "convex/server";
import migrations from
"@convex-dev/migrations/convex.config";
import rateLimiter from
"@convex-dev/rate-limiter/convex.config";
const app = defineApp();
app.use(migrations);
app.use(rateLimiter);
export default app;
export const create = mutation({
args: {
name: v.string(),
email: v.string(),
age: v.number(),
orgId: v.id("organizations"),
},
handler: async (ctx, args) => {
return ctx.db.insert("users", args);
},
});
How it works
Three steps: connect, introspect, generate. Takes about 30 seconds on a real schema.
sunsetter wizard
Interactive guided setup
sunsetter generate --db postgres --url <conn>
Generate code only, no data move
sunsetter migrate --mode schema-and-data
Full migration with data transfer
sunsetter introspect
Print schema analysis without writing
sunsetter preflight
Validate before migrating
sunsetter --mcp
Start MCP server for Claude
Claude MCP Integration
SunSetter ships a built-in Model Context Protocol server. Connect it to Claude Code or Claude Desktop and let the AI analyze your schema, plan the migration, and run the tool — without leaving your conversation.
sunsetter --mcp
Free and open source
MIT-licensed. Use it, fork it, contribute to it. If you have a complex migration and want hands-on help, consulting is available.