One-package quickstart (Vercel)
A deployed instance, on a free plan, in about five minutes. Everything here is in the repository npx create-snagset writes for you.
1. Scaffold and push
npx create-snagset my-review
cd my-review
git init && git add . && git commit -m "Snagset"
Push it to GitHub. Check .env is not in the commit — the scaffold's .gitignore covers it, and it holds your signing key.
2. Import it into Vercel
Add the project from your GitHub repository. Vercel finds vercel.json and api/index.js; there is no framework preset to choose and no build command to set.
3. Add a Postgres
From the Vercel marketplace — Neon and Supabase both work, and both have a free tier. Vercel sets DATABASE_URL for you.
Use the pooled connection string if you are offered a choice. Serverless functions open a connection per instance, and a pooler is what stops that exhausting the database's limit.
4. Set the signing key
Copy SNAGSET_SECRET_KEY from your local .env into the project's environment variables, and SNAGSET_BASE_URL to your deployment's URL.
The key is required here, unlike locally. Running on your own machine, the server generates one to .snagset/secret.key on first boot. A serverless filesystem is ephemeral, so each instance would invent a different key — a session minted by one would fail to verify on the next, and an encrypted credential written by one would be unreadable by all the others. The server refuses to start without it and says so.
5. Migrate on deploy, not on boot
Set the build command to:
npx snagset migrate
Migrations take an advisory lock. On a long-running server that happens once, at startup; on serverless there is no startup to hook, and migrating on a cold request would put every instance behind the one applying DDL — on somebody's first page load. So it is a deploy step.
6. Claim it
Open your deployment. The logs print a claim URL; open it, set a password.
Or claim it without a browser by setting the four bootstrap variables before the first deploy — see self-hosting.
What you get
vercel.json already schedules the job runner:
{ "crons": [{ "path": "/api/jobs/run", "schedule": "* * * * *" }] }
That is what expires review links, downgrades write mode after the grace window, reaps unbound attachments and sends queued notifications. Set CRON_SECRET in the environment — the route returns 503 until you do, rather than running unauthenticated.
Costs, honestly
| Free tier | When you outgrow it | |
|---|---|---|
| Vercel | Hobby, for non-commercial use | Pro, if you are billing clients |
| Neon / Supabase | ~0.5 GB | A few euros a month |
| Screenshots | — | An S3-compatible bucket, cents per month |
Vercel's Hobby plan forbids commercial use. If you are billing clients for this work, that is a Pro plan — or any Node host, since the same package runs with npm start.
Or anywhere else
Nothing here is Vercel-specific except vercel.json. Railway, Render, Fly and a plain VPS all take the same repository with npm start, and the compose file runs it with Postgres included.