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:
- Go to Settings → Environment Variables
- Add each variable from
.env.example - 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:
- Checks out code
- Installs dependencies
- Lints and tests
- Builds
- Only deploys if all previous steps pass
Add your Vercel credentials as GitHub Secrets:
- Go to Settings → Secrets and variables → Actions
- Add
VERCEL_TOKEN(fromvercelCLI) - Add
VERCEL_ORG_IDandVERCEL_PROJECT_ID(fromvercelCLI)
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:
- In Vercel dashboard, go to Settings → Git
- Set "Preview Deployments" to build from all branches
- Push to a
stagingbranch and Vercel auto-builds a preview URL
Now your workflow is:
- Feature branch → Pull Request → Preview deployment (automatic)
- Code review
- Merge to
staging→ Staging environment (for QA) - 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:
- Go to Deployments tab
- Click the previous working deployment
- 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
| Step | Done | Notes |
|---|---|---|
Test locally: npm run build && npm run preview | ☐ | Verify production build works |
Lint passes: npm run lint | ☐ | No eslint errors |
Tests pass: npm run test | ☐ | All unit tests green |
| Environment variables set in production | ☐ | Check Vercel dashboard |
| API endpoints use config imports | ☐ | No hardcoded localhost:3000 |
| Health check endpoint available | ☐ | GET /health returns 200 |
| Monitoring alerts configured | ☐ | Uptime robot or similar |
| Rollback procedure tested | ☐ | Can rollback in <5 min |
| Analytics/error tracking enabled | ☐ | Sentry, 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.