Deployment Guide
Step-by-step instructions for deploying Loop on Vercel or manually on your own infrastructure.
Deployment Guide
Loop is a Turborepo monorepo with three deployable apps. This guide covers deploying the API server and Dashboard. The marketing site (@loop/web) is optional for self-hosting.
Prerequisites
Before deploying, make sure you have:
- A PostgreSQL 15+ database (Neon recommended for Vercel deployments)
- All required environment variables ready
- Node.js 20+ installed (for manual deployments)
Vercel Deployment
Vercel is the recommended deployment platform. The Hono API server auto-detects the Vercel Functions runtime, and the React dashboard deploys as a static site.
Deploy the API
Import the repository
Go to vercel.com/new and import your Loop repository from GitHub.
Configure the project
Set the Root Directory to apps/api. Vercel will detect it as a Node.js project.
Set the Build Command to:
pnpm run buildSet the Output Directory to dist.
Set environment variables
In the Vercel project settings, add the following environment variables:
DATABASE_URL-- Your Neon PostgreSQL connection stringLOOP_API_KEY-- A secure API key (see Environment Variables for generation instructions)
Add webhook secrets only if you plan to use those integrations:
GITHUB_WEBHOOK_SECRETSENTRY_CLIENT_SECRETPOSTHOG_WEBHOOK_SECRET
Run database migrations
After the first deployment, run migrations against your production database. You can do this from your local machine with the production DATABASE_URL:
DATABASE_URL="your-production-connection-string" pnpm run --filter @loop/api db:migrateDeploy
Click Deploy. Vercel will build the API and deploy it as serverless functions. The API will be available at your Vercel project URL (e.g., https://loop-api.vercel.app).
Deploy the Dashboard
Create a separate Vercel project
Import the same repository again as a new Vercel project. Set the Root Directory to apps/app.
Set the Build Command to:
pnpm run buildSet the Output Directory to dist.
Set environment variables
VITE_API_URL-- The URL of your deployed API (e.g.,https://loop-api.vercel.app)VITE_LOOP_API_KEY-- The same API key you set asLOOP_API_KEYon the API server
Deploy
Click Deploy. The dashboard will be available at your Vercel project URL (e.g., https://loop-app.vercel.app).
The dashboard embeds the API key into the client-side bundle at build time. Only deploy the dashboard behind authentication or restrict access to trusted networks.
Manual Deployment
For deployments on your own infrastructure (VPS, EC2, bare metal, etc.).
Build the Apps
From the repository root, install dependencies and build all apps:
pnpm install
pnpm run buildThis produces:
apps/api/dist/-- Compiled API serverapps/app/dist/-- Static dashboard files
Set Up the Database
Provision PostgreSQL
Set up a PostgreSQL 15+ instance. You can use:
- Neon (serverless, free tier available)
- Self-hosted PostgreSQL
- Any managed PostgreSQL service (AWS RDS, Google Cloud SQL, etc.)
Configure the connection
Set the DATABASE_URL environment variable:
export DATABASE_URL="postgresql://user:password@host:5432/loop"Run migrations
Apply the database schema:
pnpm run --filter @loop/api db:migrateThis creates all required tables. Run this command again after pulling updates that include new migrations.
Run the API Server
Set the required environment variables and start the server:
export DATABASE_URL="postgresql://user:password@host:5432/loop"
export LOOP_API_KEY="loop_your_secret_key_here"
# Start the API server (port 4242 by default)
node apps/api/dist/index.jsThe API server listens on port 4242 by default. Place it behind a reverse proxy (nginx, Caddy, etc.) for TLS termination and custom domains.
In production, use a process manager like PM2 or systemd to keep the API running and restart it on failure.
Serve the Dashboard
The dashboard build output (apps/app/dist/) is a set of static files. Serve them with any web server:
Using nginx:
server {
listen 80;
server_name app.example.com;
root /path/to/loop/apps/app/dist;
location / {
try_files $uri $uri/ /index.html;
}
}Using Caddy:
app.example.com {
root * /path/to/loop/apps/app/dist
try_files {path} /index.html
file_server
}The try_files directive is required because the dashboard is a single-page application with client-side routing.
Remember to set VITE_API_URL and VITE_LOOP_API_KEY before building the dashboard, since these
values are embedded at build time.
Health Check
Verify the API is running by hitting the health endpoint:
curl https://your-api-url/healthExpected response:
{
"ok": true,
"service": "loop-api",
"timestamp": "2026-02-20T12:00:00.000Z"
}