supabase-selfhosted-cli
v0.2.20
Published
CLI for self-hosted Supabase — deploy edge functions, push migrations, and sync types (VPS, Docker, local)
Maintainers
Readme
Supabase Selfhosted CLI
CLI for self hosted Supabase — on a VPS, in Docker on a remote server, or running locally on your machine. Wraps the repetitive work you do by hand: deploy edge functions, restart the runtime, push migrations, and regenerate TypeScript types.
As featured on https://spyke.social

So you've figured out how to use the port numbers to push migrations and sync types using the regular Supabase CLI. And credit where credit is due, Supabase really does work quite well with the " - db-url" flag. However, the entire process leaves something to be desired. Especially when dealing with real-time edge functions, as you have to keep tossing in the scp command with the right path, type in the VPS password and then restart the docker container.
Install
yarn global add supabase-selfhosted-clior
npm install -g supabase-selfhosted-cliOr run from source:
git clone https://github.com/spykesocial/supabase-selfhosted-cli.git
cd supabase-selfhosted-cli
npm install
npm linkYou still need the Supabase CLI installed for db push and gen types (this package shells out to it). Supabase CLI also uses docker to create its own copy of the remote instance so you'll need docker installed when generating types.
Quick start
From your project root (where supabase/migrations lives):
supabase-selfhosted-clior if you just want to setup
supabase-selfhosted-cli setupThe wizard asks where your instance runs:
- Local machine — Docker / Docker Compose on this computer (copies files directly to your volume mount, runs restart locally)
- Remote server — VPS or cloud VM over SSH (SFTP upload + remote restart)
Remote server (VPS) example
| Setting | Example |
| --------------------- | ------------------------------------------------- |
| SSH user | root |
| Server IP | 203.0.113.10 |
| Functions destination | /etc/supabase/volumes/functions |
| SSH password | stored once in ~/.supabase-selfhosted-cli/ |
| Postgres tenant id | your-tenant-id (from postgres.your-tenant-id) |
| DB password | your pooler password |
| Migration port | 5453 |
| Types port | 6438 |
| Restart command | e.g. docker restart <edge-container> |
Local Docker example
| Setting | Example |
| --------------------- | ---------------------------------------------------------------------------------------------- |
| Functions destination | /path/to/supabase/docker/volumes/functions (absolute path to your edge-runtime volume mount) |
| Database host | 127.0.0.1 |
| Migration port | 5432 (or your exposed Postgres port) |
| Types port | 5432 (or your exposed Postgres pooler port) |
| Restart command | docker compose restart edge-runtime or auto-detect edge container |
Setup creates .supabase-selfhosted-cli.json in your project so commands know which environment(s) to use.
Commands
Deploy edge functions
Remote (SSH) — replaces:
scp -r supabase/functions/. [email protected]:/etc/supabase/volumes/functions
ssh [email protected] 'docker restart ...'Local (Docker) — replaces manually copying into your Docker volume and restarting containers.
supabase-selfhosted-cli functions deployFlags:
--restart— always restart after deploy--no-restart— never restart--prune— remove destination files/folders not present locally (use after deleting a function)- default — prompts based on your setup preference
End-to-end verification against a configured project:
npm run build
./scripts/e2e-deploy-test.sh /path/to/your-projectPush migrations
Replaces:
PGSSLMODE=disable npx supabase db push --db-url 'postgresql://postgres.your-tenant-id:...@host:5453/postgres?sslmode=disable' --yesSelf-hosted Supavisor typically has no TLS. Recent Supabase CLI versions require TLS for remote --db-url hosts, so this CLI sets PGSSLMODE=disable (and sslmode=disable on the URL). That is also why bare npx supabase db push --db-url ... fails with tls error (server refused TLS connection) while the same command with --debug succeeds.
supabase-selfhosted-cli db push
supabase-selfhosted-cli db push --debugGenerate TypeScript types
Replaces:
PGSSLMODE=disable npx supabase gen types typescript --db-url 'postgresql://...@host:6438/postgres?sslmode=disable' --schema public > database.types.tssupabase-selfhosted-cli gen types
supabase-selfhosted-cli gen types -o database.types.tsManage credentials
supabase-selfhosted-cli settings- Show masked configuration
- Re-run setup wizard
- Delete stored credentials
Configuration storage
- Environments:
~/.supabase-selfhosted-cli/profiles/<name>.json(mode600) - Project link:
.supabase-selfhosted-cli.jsonin your repo
Passwords are stored locally on your machine. Delete them anytime via supabase-selfhosted-cli settings.
Multiple projects / environments
One repo can link to multiple environments (for example development and production). Credentials live in ~/.supabase-selfhosted-cli/profiles/; the project link file stores the linked set plus which environment is active.
.supabase-selfhosted-cli.json shape:
{
"environments": ["development", "production"],
"projectId": "<uuid>"
}Legacy single-field { "profile": "…" } and multi-field { "profiles": […] } links still work and upgrade automatically.
From a project directory:
# See linked projects and environments
supabase-selfhosted-cli projects --list
# First time — creates an environment (folder name, or pick development / production)
supabase-selfhosted-cli setup
# Add another environment without replacing the first
supabase-selfhosted-cli projects --link
# Change which environment commands use by default
supabase-selfhosted-cli projects --switch
# Edit SSH/DB credentials for an environment
supabase-selfhosted-cli projects --edit
# Remove stored credentials for an environment
supabase-selfhosted-cli projects --deleteUse -e to target an environment for a single command (does not change the active default):
supabase-selfhosted-cli setup --environment production
supabase-selfhosted-cli db push --environment production
supabase-selfhosted-cli functions deploy --environment productionRestart command tips
Self-hosted setups differ. During setup, the CLI suggests a mount-scoped restart command derived from your functions path. It finds the edge-functions container that mounts that exact path — important on Dokploy/Coolify, where the compose folder id can differ from the Docker container name (e.g. folder ...-oy2cqz vs container ...-8rcgv9-supabase-edge-functions).
# Mount-scoped (recommended; auto-suggested)
# Finds the container whose volume source is your functions path, then restarts it.
# Explicit container name (if you already know it)
docker restart financial-wisdom-supabase-8rcgv9-supabase-edge-functions
# Docker Compose from that stack's directory
cd /etc/dokploy/compose/financial-wisdom-supabase-oy2cqz && docker compose restartAvoid host-wide greps like grep -i edge | head -n 1 when the server runs multiple Supabase projects.
Roadmap
- OS keychain integration for secrets
- Remote environment sync for teams
- Migration status, function diff, and health checks
License
MIT
