What you will have

This guide is for self-host only. Supatype Cloud (managed Kubernetes) is a separate product and not covered here.

1 · Create the project locally

On your machine (Node.js 22+):

npm install -g @supatype/cli

mkdir my-blog && cd my-blog
supatype init
npm install
supatype keys

Copy the printed ANON_KEY and SERVICE_ROLE_KEY into .env for local dev.

Static frontend (one-time)

supatype app add --static ./public
# Add a build step to package.json, e.g. Vite → public/
npm install -D vite
# "build": "vite build"  (outputDir: public)

Commit supatype.config.ts — do not run app add again on the server.

Develop locally

supatype dev
supatype push

Optional: supatype.local.config.ts on your laptop only (proxy to Vite) while production stays static in the main config. See Deploy changes.

git init
git add .
git commit -m "Initial Supatype project"
git branch -M main
git remote add origin [email protected]:YOUR_USER/my-blog.git
git push -u origin main

2 · Prepare the VM (one-time)

Ubuntu 22.04+ (or similar) with SSH access. Install Docker, Compose v2, Node 22, and the CLI:

# Docker — see https://docs.docker.com/engine/install/ubuntu/
sudo apt update && sudo apt install -y git nodejs npm
sudo npm install -g @supatype/cli

sudo mkdir -p /opt/my-blog
sudo chown "$USER":"$USER" /opt/my-blog
cd /opt/my-blog
git clone [email protected]:YOUR_USER/my-blog.git .

Production secrets on the VM

Create /opt/my-blog/.env on the server (never commit this file). Use strong values and your public URL:

DATABASE_URL=postgresql://supatype_admin:CHANGE_ME@localhost:5432/my-blog
POSTGRES_USER=supatype_admin
POSTGRES_PASSWORD=CHANGE_ME
POSTGRES_DB=my-blog
JWT_SECRET=CHANGE_ME-long-random-string
ANON_KEY=eyJ...   # from supatype keys on first setup
SERVICE_ROLE_KEY=eyJ...
API_EXTERNAL_URL=https://api.example.com
SITE_URL=https://example.com

First boot on the VM

cd /opt/my-blog
npm install
supatype self-host compose render
supatype self-host compose up -d
supatype push
npm run build
supatype self-host compose render
supatype self-host compose up -d

Open http://YOUR_VM_IP:18473 (put Nginx/Caddy in front for HTTPS). Studio: /studio/.

3 · GitHub repository secrets

In your repo: Settings → Secrets and variables → Actions. Add:

The workflow does not upload .env; production secrets stay only on the VM.

4 · GitHub Actions workflow

Add .github/workflows/deploy-self-host.yml to your repo:

name: Deploy self-host

on:
  push:
    branches: [main]
  workflow_dispatch:

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy over SSH
        uses: appleboy/[email protected]
        with:
          host: ${{ secrets.VM_HOST }}
          username: ${{ secrets.VM_USER }}
          key: ${{ secrets.VM_SSH_KEY }}
          script_stop: true
          script: |
            set -euo pipefail
            cd "${{ secrets.DEPLOY_PATH }}"
            git fetch origin main
            git reset --hard origin/main
            npm ci
            supatype push
            npm run build
            supatype self-host compose render
            supatype self-host compose up -d

On every push to main, the VM pulls latest code, applies schema migrations, rebuilds public/, and refreshes Compose.

supatype push uses DATABASE_URL from the VM’s .env (Postgres exposed on localhost:5432 by Compose). Install @supatype/cli globally on the VM, or change the script to npx supatype@latest.

5 · Verify the pipeline

# Local: change schema or frontend, then
git add .
git commit -m "Add posts table and update landing page"
git push origin main

Watch the Action in GitHub → Actions. On success, hit your gateway URL and confirm schema + static files updated.

Troubleshooting

Related docs

Local development · Self-host · Deploy changes