Skip to main content

Deploying React SaaS Dashboards to Production

Deploying a SaaS dashboard to production means more than uploading files to a server. It means continuous integration, automated testing, environment secrets, monitoring, and rollback strategies. The best platforms (Vercel, Netlify, AWS) automate most of this, but you need to understand the flow to avoid deploying broken code or leaking API keys.

I deployed a dashboard to AWS S3 once without proper CI/CD, and a teammate pushed broken code that deleted production data before we could rollback. Now, all our SaaS dashboards use automated testing, deployment checks, and staging environments. This article teaches you the reliable way.

What You'll Learn

You'll configure:

  • Automated deployment pipelines with GitHub Actions
  • Environment variables and secrets management
  • Staging and production environments
  • Zero-downtime deployments
  • Uptime monitoring and alerting
  • Rollback and recovery procedures

Prerequisites

You need a GitHub repository with your dashboard code. A Vercel account is easiest (free tier available), but AWS and Netlify alternatives are covered. Understanding of Git, environment variables, and CI/CD is helpful.

Step 1: Prepare Your Code for Production

Add a build script to package.json:

{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"test": "vitest",
"lint": "eslint src --ext .ts,.tsx"
}
}

Create an .env.example file documenting all required environment variables:

VITE_API_URL=https://api.example.com
VITE_STRIPE_PUBLIC_KEY=pk_test_...
VITE_WS_URL=wss://api.example.com/ws

Never commit .env files. Add to .gitignore:

.env
.env.local
.env.*.local
dist/
node_modules/

Step 2: Deploy to Vercel

Vercel is the easiest option for React apps. Install the CLI:

npm install -g vercel

Log in and link your project:

vercel login
vercel link

Create a vercel.json configuration:

{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"env": {
"VITE_API_URL": "@vite_api_url",
"VITE_STRIPE_PUBLIC_KEY": "@vite_stripe_public_key"
},
"rewrites": [
{
"source": "/(.*)",
"destination": "/index.html"
}
]
}

The rewrites ensure that client-side routes work (e.g., /dashboard loads index.html, then React Router handles routing).

Add environment variables in the Vercel dashboard:

  1. Go to Settings → Environment Variables
  2. Add each variable from .env.example
  3. Set them for Preview and Production separately (staging values vs. production values)

Deploy:

vercel deploy --prod

Vercel auto-generates a live URL and enables HTTPS. Your dashboard is live.

Step 3: Set Up GitHub Actions for CI/CD

Create .github/workflows/deploy.yml:

name: Deploy to Vercel

on:
push:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'

- name: Install dependencies
run: npm install

- name: Lint
run: npm run lint

- name: Run tests
run: npm run test

- name: Build
run: npm run build

deploy:
needs: test
runs-on: ubuntu-latest
if: success()
steps:
- uses: actions/checkout@v4

- name: Deploy to Vercel
uses: vercel/actions/deploy-production@v23
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}

This workflow:

  1. Checks out code
  2. Installs dependencies
  3. Lints and tests
  4. Builds
  5. Only deploys if all previous steps pass

Add your Vercel credentials as GitHub Secrets:

  1. Go to Settings → Secrets and variables → Actions
  2. Add VERCEL_TOKEN (from vercel CLI)
  3. Add VERCEL_ORG_ID and VERCEL_PROJECT_ID (from vercel CLI)

Now every push to main triggers this workflow. If linting or tests fail, deployment is blocked.

Step 4: Set Up Staging Environment

Create a separate vercel.json for staging:

vercel env pull .env.staging

Or create a staging branch and configure Vercel to auto-deploy it:

  1. In Vercel dashboard, go to Settings → Git
  2. Set "Preview Deployments" to build from all branches
  3. Push to a staging branch and Vercel auto-builds a preview URL

Now your workflow is:

  1. Feature branch → Pull Request → Preview deployment (automatic)
  2. Code review
  3. Merge to staging → Staging environment (for QA)
  4. Merge to main → Production deployment (automated)

Step 5: Environment Variables and Secrets

In production, never hardcode API URLs or keys. Use environment variables:

Create src/config.ts:

export const config = {
apiUrl: import.meta.env.VITE_API_URL || 'http://localhost:3000/api',
stripePublicKey: import.meta.env.VITE_STRIPE_PUBLIC_KEY || '',
wsUrl: import.meta.env.VITE_WS_URL || 'ws://localhost:3000/ws',
environment: import.meta.env.MODE,
};

if (!config.stripePublicKey) {
console.warn('VITE_STRIPE_PUBLIC_KEY is not set');
}

Then import and use it everywhere:

import { config } from './config';

const response = await fetch(`${config.apiUrl}/users`);

In Vercel, set production values in the dashboard (Settings → Environment Variables). Staging gets different values automatically via branch-based overrides.

Step 6: Monitor Your Deployment

Add uptime monitoring to catch issues fast. Services like Uptime Robot (free tier) ping your dashboard every 5 minutes:

https://yourdashboard.vercel.app/health

Create a simple health check endpoint in your React app. Since Vercel serves static files, use a public/health.txt file or a serverless function:

Create api/health.js (Vercel Serverless Function):

export default function handler(request, response) {
response.status(200).json({ status: 'ok', timestamp: new Date().toISOString() });
}

Or check external API connectivity from your frontend:

export async function checkHealth() {
try {
const response = await fetch(`${config.apiUrl}/health`, { signal: AbortSignal.timeout(5000) });
return response.ok;
} catch {
return false;
}
}

Set up alerts in your monitoring tool to notify you if the dashboard goes down.

Step 7: Rollback Procedures

If you deploy broken code, rollback in seconds:

With Vercel:

  1. Go to Deployments tab
  2. Click the previous working deployment
  3. Click "Promote to Production"

With GitHub: Create a manual rollback workflow:

name: Rollback to Previous Deployment

on:
workflow_dispatch:
inputs:
commitSha:
description: 'Commit SHA to deploy'
required: true

jobs:
rollback:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.commitSha }}

- name: Deploy
run: vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }}

Trigger this from the GitHub Actions tab if needed.

Deployment Checklist

StepDoneNotes
Test locally: npm run build && npm run previewVerify production build works
Lint passes: npm run lintNo eslint errors
Tests pass: npm run testAll unit tests green
Environment variables set in productionCheck Vercel dashboard
API endpoints use config importsNo hardcoded localhost:3000
Health check endpoint availableGET /health returns 200
Monitoring alerts configuredUptime robot or similar
Rollback procedure testedCan rollback in <5 min
Analytics/error tracking enabledSentry, DataDog, etc.

Key Takeaways

  • Automate testing and deployment with CI/CD so broken code never reaches production.
  • Use environment variables for secrets and API endpoints, never hardcode them.
  • Separate staging and production environments so you can test safely before going live.
  • Monitor uptime and error rates 24/7. Set up alerts so you know about issues before customers do.
  • Practice rollback procedures so you can revert broken deployments in seconds, not hours.
  • Vercel's preview deployments let you test each PR before merging, reducing production incidents by 70–90%.

Frequently Asked Questions

What if I need to rollback but can't access Vercel?

Use GitHub Actions: commit a rollback workflow trigger and manually run it from GitHub.com. Or, set up a simple CLI script: vercel rollback --to=<commit-sha>.

How do I handle database migrations on deploy?

For Vercel (static hosting), migrations run separately—they're not part of the frontend deployment. Deploy the backend first, run migrations, then deploy the frontend. Or use a "pre-deploy" Vercel Function that runs migrations.

Should I use Vercel or self-host on AWS?

Vercel is easier (no DevOps), cheaper for small projects, and has amazing DX. Self-hosting on AWS is cheaper at scale and gives more control. For SaaS starting out, Vercel wins. For mature SaaS with 1M+ users, self-hosting makes sense economically.

How do I know if my production deployment is working?

Set up a simple health check: curl https://yourdashboard.vercel.app && echo "OK". Or monitor your analytics for spike in errors. Or use Sentry to catch exceptions in production.

Can I deploy multiple dashboards from one repo?

Yes, use monorepos (pnpm workspaces or Yarn workspaces) and configure each dashboard as a Vercel project pointing to different outputDirectory values in separate vercel.json files.

Further Reading