Migrate to koigrid

Move your stack from AWS/Vercel/Railway/Render piece by piece — each step is reversible. Postgres migrates with near-zero downtime via logical replication (CDC), so you cut over when lag is 0.

1. Postgres

Simple: dump + restore. Near-zero-downtime: logical replication streams your source into koigrid; cut over at lag 0.

# 1) Create the managed database + get its URL
koigrid db create prod --version 16
DATABASE_URL="$(koigrid db connection <id> --json | jq -r .connection.uri)"

# --- Simple (dump + restore) ---
pg_dump "$SOURCE_URL" | psql "$DATABASE_URL"        # or: drizzle-kit migrate / prisma migrate deploy

# --- Near-zero-downtime (logical replication / CDC) ---
# a) on your SOURCE (e.g. RDS with rds.logical_replication=1):
#      CREATE PUBLICATION mig FOR ALL TABLES;
# b) copy the SCHEMA to koigrid first (tables must exist):
pg_dump --schema-only "$SOURCE_URL" | psql "$DATABASE_URL"
# c) on koigrid (the app user has REPLICATION — no superuser needed):
#      CREATE SUBSCRIPTION mig CONNECTION 'postgresql://user:pass@source-host:5432/db' PUBLICATION mig;
# d) watch lag → 0:   SELECT * FROM pg_stat_subscription;
# e) cut over (point the app at koigrid), then:  DROP SUBSCRIPTION mig;

2. Storage (S3)

Your bucket already speaks S3 — copy objects with rclone or aws-cli, then repoint your client’s endpoint + keys.

koigrid storage buckets create assets
koigrid storage keys                     # → accessKey / secretKey / endpoint (shown once)

# copy objects from your old S3 (rclone remote 'koigrid' → https://s3.koigrid.com, path-style)
rclone copy s3old:my-bucket koigrid:assets

# then repoint your S3 client: endpoint=https://s3.koigrid.com, forcePathStyle=true,
# new keys, and use the bucketName koigrid returns (not the friendly name).

3. App

Deploy from a git repo, a container image, or your local folder (--dir, no git/Docker needed). Set env vars, then a custom domain.

# from a git repo (add --repo-token for a private repo):
koigrid apps deploy web --repo https://github.com/you/app
# ...or straight from your local folder (no git, no Docker):
koigrid apps deploy web --dir ./

# env vars (invalid lines are reported, not fatal; saved even before the first deploy):
curl -X POST $API/apps/<id>/env -H "Authorization: Bearer koi_KEY" \
  -d '{"env":{"DATABASE_URL":"...","API_KEY":"..."}}'

# custom domain + automatic TLS:
koigrid apps domains web app.yourdomain.com

4. Cron jobs

Your EventBridge/cron endpoints become HTTP jobs — koigrid hits the URL on schedule with your secret header.

# an EventBridge/cron endpoint → an HTTP job (koigrid calls the URL on schedule):
koigrid jobs create nightly --schedule "0 3 * * *" \
  --url https://app.yourdomain.com/api/cron/report --header "x-cron-secret: $SECRET"

# ...or a container job:
koigrid jobs create backup --schedule "0 2 * * *" --image alpine --command "sh -c '…'"

5. Cutover

Point DNS at koigrid with a rollback ready. Bandwidth is included and flat — no egress surprise on the way out of AWS.

# point your DNS at koigrid, keep the old stack ready to roll back.
# bandwidth is included + flat — no egress bill on the way out of AWS.