Skip to main content
This guide walks through deploying Harp to production by hand. There is no CLI, npx script, or one-shot runbook yet that does all of this for you. One is planned, but for now you deploy manually, and this page describes each step in depth. The recommended stack is the cheapest way to run Harp:

How the platform ships

The Dockerfile is a multi-stage build that produces one image:
  1. Builds the portal (client/portal) into static files.
  2. Builds a static Go binary.
  3. Ships both in a scratch image. The Go binary serves the API and the portal’s static files on port 8080.
One container is the whole platform.

Prerequisites

  • A Google Cloud account with billing enabled, plus the gcloud CLI
  • A Neon account
  • A SendGrid account (or SMTP credentials)
  • Your fork of the harp repo on GitHub

Step 1: Create the Google Cloud project

Enable the services the deployment needs:
Pick a region close to your school (the examples below use us-south1) and grab the project number:
The default compute service account (COMPUTE_SA) is what Cloud Run and Cloud Build will run as. Give it the roles the pipeline needs:
The serviceAccountTokenCreator grant is required: the API uses it to sign GCS upload URLs.

Step 2: Create the database on Neon

Create a Neon project and a database. Use the pooled connection string for the API; keep it aside as DB_ADDR. Set DB_MAX_OPEN_CONNS=15 or so, since each Cloud Run instance opens its own pool. Run the migrations against it once from your machine:

Step 3: Stand up SuperTokens

Use SuperTokens’ managed service, which is free under 5,000 monthly active users. This is what HackUTD runs on. Sign up at supertokens.com, create a core, and copy the connection URI and API key into SUPERTOKENS_CONNECTION_URI and SUPERTOKENS_API_KEY. If you expect to exceed the free tier, the core is open source and self-hostable. It needs a Postgres database (a second database in the same Neon project works). Deploy it as its own Cloud Run service:
The service URL becomes SUPERTOKENS_CONNECTION_URI and the key becomes SUPERTOKENS_API_KEY. Only the Harp backend should be talking to it.

Step 4: Create the storage bucket

The bucket stays private; the API hands out short-lived signed URLs. Browsers upload resumes directly to GCS, so the bucket needs CORS for your app’s origin:
You won’t know YOUR_APP_URL until step 6 creates the Cloud Run service, so come back and update the CORS file then.

Step 5: Set up continuous deployment

Create an Artifact Registry repository for the images:
Then connect Cloud Build to your GitHub repo (a one-time browser step: install the Cloud Build GitHub App and authorize your fork) and create a push trigger on main that builds with the repo’s Dockerfile, pushes the image tagged with the commit SHA, and deploys it with gcloud run services update. The Cloud Run console can generate this trigger for you: create the service with “Continuously deploy from a repository”. This is how HackUTD runs it. After that, every merge to main deploys itself.

Step 6: Create the Cloud Run service

The service configuration that has worked in practice:
  • 1 vCPU, 512 MiB memory, CPU startup boost on
  • Concurrency 80, request timeout 300s
  • Minimum instances 0, maximum around 20
  • Port 8080, public ingress
Set the environment variables from the environment reference. The required set is AUTH_BASIC_USER, AUTH_BASIC_PASS, SUPERTOKENS_CONNECTION_URI, and SUPERTOKENS_API_KEY; a real deployment also sets ENV=prod, APP_URL (the Cloud Run URL), DB_ADDR, GCS_BUCKET_NAME, the email settings, PUBLIC_API_KEY, HACKATHON_NAME, and the VAPID keys (task gen-vapid generates a pair). Put secrets in Secret Manager rather than plaintext env vars, and reference them from the service:
APP_URL is the service’s own URL, which doesn’t exist until the first deploy. Deploy once, read the URL, set APP_URL, and deploy again. Update the GCS CORS config from step 4 with the same URL. If you want “Sign in with Google”, create an OAuth web client in the Google Auth Platform console:
  1. Configure the consent screen with your team’s support email.
  2. Create a web application client.
  3. Add your APP_URL as an authorized JavaScript origin.
  4. Add APP_URL/auth/callback/google as an authorized redirect URI.
  5. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET on the Cloud Run service.
Add the localhost equivalents (http://localhost:3000 and its callback) if you want Google login in local dev against the same client.

Step 8: Deploy the marketing site

The marketing site is a separate Vercel project. Import the repo into Vercel, then set HARP_API_BASE_URL to your Cloud Run URL and HARP_PUBLIC_API_KEY to the same value as the backend’s PUBLIC_API_KEY, for both Production and Preview. See The marketing site for details.

Step 9: Verify

  • Open APP_URL and confirm the portal loads.
  • Create an account, sign in, and complete super-admin onboarding.
  • Upload a resume in a test application to confirm the GCS signing path and CORS.
  • Send yourself a decision email to confirm the email provider.
  • curl -H "X-API-Key: ..." APP_URL/v1/public/schedule to confirm the public API.

Releases and upgrades

Releases are automated with release-please: Conventional Commits on main accumulate into a release PR, and merging it cuts a tagged release. The CD trigger deploys every merge to main. Adopters upgrade by merging release tags into their fork, see Forking & staying upstream.
A CLI that automates this setup is planned. Until then, this manual path is the supported one.