Starter application repository for supabase-headless: a pinned Git submodule plus the app-owned shell.
Use this when you want a product backend that vendors the headless stack instead of forking or copying it. The stack owns the data plane; this repo owns product SQL, functions, secrets, and compose overrides.
| This template owns | The vendor submodule owns |
|---|---|
Root compose.yml include + mounts |
Base services and default wiring |
Root .env / .env.example |
Platform env contract + generate-keys.mjs |
db/app/migrations/ |
Postgres image, bootstrap, stack migrations, migrator |
functions/ |
Edge Runtime loader and @stack/* helpers |
| Optional host mounts (e.g. Caddy logs) | Gateway, Auth, REST, Realtime, Storage, … |
Do not edit files under vendor/supabase-headless for product work. Bump the submodule pin instead. Full ownership and override rules: VENDORING.md.
.
├── compose.yml # include vendor compose + app mounts
├── .env.example # platform contract (+ APPLICATION section)
├── db/app/migrations/ # product SQL (-*.sql drafts are skipped)
├── functions/ # product Edge Functions
├── logs/caddy/ # created at runtime (gitignored)
└── vendor/supabase-headless/ # pinned submodule
On GitHub: Use this template, or clone and re-point origin:
git clone --recurse-submodules https://github.com/gatherpeers/supabase-headless-app-template.git my-app
cd my-appIf you cloned without submodules:
git submodule update --init --recursivecp .env.example .env
node vendor/supabase-headless/generate-keys.mjs --update-envWithout local Node, copy the Docker one-liner from the header of generate-keys.mjs and prefix the script with vendor/supabase-headless/ (Command Prefix).
docker compose up -dExample function (after the stack is up):
GET https://localhost/functions/v1/hello?name=Pau
Local HTTPS CA (when PUBLIC_API_DOMAIN=localhost):
docker compose cp gateway:/data/caddy/pki/authorities/local/root.crt ./caddy-local-root.crt- SQL — add numbered files under
db/app/migrations/(see-example.sqlfor a suggested split). Files prefixed with-are drafts and are not applied. - Functions — add directories under
functions/with anindex.ts. Keep usingvolumes: !overrideso the vendor examples are not mounted. - Env — set domains, SMTP, OAuth, CORS, and other product values in the root
.env. Append app-only variables under theAPPLICATIONsection. - Compose — add service overrides or sidecars in the root
compose.yml; attach them toprivate_net(andpublic_netonly if they need outbound internet).
Day-to-day stack operation, production hardening, and service docs live in the supabase-headless README.
When supabase-headless publishes a new release tag:
cd vendor/supabase-headless
git fetch --tags
git checkout vX.Y.Z
cd ../..
git add vendor/supabase-headless
git commit -m "Bump supabase-headless to vX.Y.Z"
# Diff .env.example against the new pin and merge any new platform vars into your .env
docker compose config
docker compose up -d
# If the functions loader or @stack helpers changed:
docker compose build functions
docker compose up -d --force-recreate --no-deps functionsKeep the committed .env.example aligned with the pinned vendor tag so new clones match the stack they check out.
docker compose ps
docker compose logs -f --tail=100
docker compose down
bash vendor/supabase-headless/db/types-gen-ts.sh public,storage,auth database.types.tsGateway access logs are written under ./logs/caddy on the host (directory is created on first start; the tree is gitignored).