Deploy your first instance
By the end you'll have a staging instance of Monark running from the develop branch: the api on Render, the web app on Vercel, Postgres and sign-in on Supabase, with you signed in as its administrator. It's for whoever will operate Monark, and takes about an hour. Production comes after, with the deploy checklist.
Before you start
- Accounts on Supabase, Render and Vercel, each with access to your copy of the Monark repository on GitHub
- A local checkout of the repository with
pnpm installdone (see Set up a development environment) openssl, which Git Bash on Windows includes
Generate the secrets
- Run this four times and store each value, labelled, in your password manager:
Label themopenssl rand -hex 32TOTP_ENCRYPTION_KEY,SECRETS_ENCRYPTION_KEY,EMAIL_ACTION_SECRETandCRON_SECRET. Each is 64 hex characters.
Create the database
- In Supabase, create a project named
monark-staging. - From Project Settings → API, copy the project URL, the publishable key and the secret key.
- From Project Settings → Database, copy the transaction pooler URL (port 6543) and the direct connection URL (port 5432), with your database password filled in.
You now have everything the api needs to reach its database.
Deploy the api
- In Render, choose New → Blueprint and pick the repository. Render lists the services in
render.yaml: production ones onmain, and-stagingones ondevelop. - Fill
monark-cron-shared-staging:CRON_SECRETwith your secret andAPI_URLwithhttps://monark-api-staging.onrender.comfor now. - Fill
monark-api-staging: the two database URLs, the Supabase URL and both keys, the two encryption keys,INITIAL_ORG_SLUG(for exampleacme) andINITIAL_ORG_NAME(for exampleAcme). SetWEB_ORIGINandAPP_URLtohttps://example.comfor now. Leave the rest blank; withoutSMTP_URLthe api logs its emails instead of sending them, which is fine for staging. - Click Apply. Leave the production services empty; they fail to start until you set them up later.
- When
monark-api-stagingis live, addEMAIL_ACTION_SECRETunder its Environment, and copy its URL intoAPI_URLinmonark-cron-shared-staging. - Check it:
You seecurl -s https://<api-host>/health{"status":"ok","service":"api"}. The database now has every table, and your organization exists.
Deploy the web app
-
In Vercel, choose Add New → Project, import the repository, and set Root Directory to
services/web. -
Add these variables, then click Deploy:
Key Value NEXT_PUBLIC_API_URLthe staging api URL NEXT_PUBLIC_APP_URLhttps://example.comfor nowNEXT_PUBLIC_SUPABASE_URL,SUPABASE_URLthe Supabase URL NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEYthe publishable key SUPABASE_SECRET_KEYthe secret key -
In Deployments, create a deployment from the
developbranch. Its stable URL ishttps://<project>-git-develop-<team>.vercel.app; this is your staging web host. -
Set
NEXT_PUBLIC_APP_URLto that host and redeploy thedevelopdeployment. -
In Render, set
WEB_ORIGINandAPP_URLonmonark-api-stagingto the same host. -
In Supabase, under Authentication → URL Configuration, set Site URL to the host and add
https://<web-host>/auth/confirmandhttps://<web-host>/auth/callbackas redirect URLs.
Open the web host: the sign-in page reads "Sign in to continue to Acme".
Make yourself the administrator
- Click Create one, enter your email and a password, and click Create account.
- Open the confirmation email from Supabase and click its link. You're signed in.
- From your local checkout, grant yourself the platform administrator role:
The command confirms the grant with your email and user id.DATABASE_URL="<direct-url>" DIRECT_URL="<direct-url>" pnpm tsx tools/sysadmin.ts grant <your-email> - Open
https://<web-host>/admin. The admin sections load.
What you built
A staging instance with its own database, deployed from develop, and an administrator account on it. Every later push to develop redeploys it.
Next steps live in Operate: set up production with the deploy checklist, connect real email, rebrand the instance, and turn on error tracking.