Everything below is free tier. Total cost: $0/month.
| Piece | Provider | Free tier |
|---|---|---|
| Frontend (React) | Vercel | Unlimited |
| Backend (Express + Socket.IO) | Render | 750 hrs/mo, sleeps on idle |
| Database (MongoDB) | MongoDB Atlas | 512 MB |
| File/Image storage | Cloudinary | 25 GB, 25k credits |
| Keep-alive bot (wakes Render) | UptimeRobot | 50 monitors |
- Render's
/tmpis wiped on deploy & after inactivity → that's why every file upload now goes to Cloudinary (seebackend/src/utils/fileStorage.js). If Cloudinary env vars are missing it falls back to local disk, which is fine for dev only. - Render free instances sleep after ~15 min idle → UptimeRobot pings
/api/healthevery 5 minutes, which wakes the instance and keeps it running. (The backend itself cannot self-ping: a sleeping process is fully suspended.) - Images display cross-origin: the frontend
resolveAsset()util prefixes the Render URL to any/uploads/...path so avatars/badges/files render on Vercel.
- Go to https://www.mongodb.com/atlas → sign up → Build a Database → Free (M0).
- Choose a region near you → create.
- Database Access → Add New User (e.g.
comflex) with a strong password. - Network Access → Add IP
0.0.0.0/0(allow all — fine for this project). - Databases → Connect → Drivers → copy the connection string, e.g.
mongodb+srv://comflex:<password>@cluster0.xxxxx.mongodb.net/comflex(replace<password>and set the DB name tocomflex).
- https://cloudinary.com → free signup.
- Dashboard shows
Cloud name,API Key,API Secret. - You'll paste all three into Render below. When set, every upload (avatars,
group avatars, badges, chat files, resources) is stored on Cloudinary and
served from
res.cloudinary.com— immune to Render restarts.
Option A — Blueprint (easiest):
- Push this repo to GitHub (it already has
render.yamlat the root). - Render → New → Blueprint → pick the repo → Render reads
render.yamland creates thecomflex-backendservice. - For every
sync: falseenv var, click Edit and fill it in:DATABASE_URL→ from step 1JWT_ACCESS_SECRET/JWT_REFRESH_SECRET→ generate:node -e "console.log(require('crypto').randomBytes(48).toString('hex'))"SEED_ADMIN_EMAIL/SEED_ADMIN_PASSWORD/SEED_ADMIN_DISPLAY_NAME→ your admin loginGOOGLE_CLIENT_ID→ from Google Cloud console (see section 5)FRONTEND_URL→ your Vercel URL, e.g.https://comflex.vercel.appCLOUDINARY_CLOUD_NAME/CLOUDINARY_API_KEY/CLOUDINARY_API_SECRET→ from step 2EMAIL_PROVIDER=brevo+EMAIL_API_KEY=xkeysib-...(Brevo API key via HTTPS port 443 — REQUIRED for Render Free Tier because Render blocks outbound SMTP ports 25/465/587) orresend+EMAIL_API_KEY=re_...EMAIL_FROM=thetarun3@gmail.com(must be a verified sender in your Brevo/Resend account)EMAIL_PROVIDER=consolefor dev/testing without keys (reset links print in Render logs)
- Apply.
Option B — Manual: Render → New → Web Service → point at the repo, root dir backend,
build npm install && npx prisma generate, start npm start, then add the same env vars.
When it's live you'll get https://comflex-backend.onrender.com. Check
https://comflex-backend.onrender.com/api/health → {"status":"ok"}.
- https://uptimerobot.com → free signup.
- Add New Monitor:
- Monitor Type: HTTP(S)
- Friendly Name:
Comflex backend - URL:
https://comflex-backend.onrender.com/api/health - Interval: 5 minutes (free tier minimum)
- Save.
- Done — Render now receives a ping every 5 min and never sleeps. (Alternative: cron-job.org or Kinsta's uptime monitor. Any HTTPS ping works.)
- https://vercel.com → import the GitHub repo → framework Vite.
- Root directory:
frontend. Build:npm run build. Output:dist. - Environment Variables (Settings → Environment Variables):
VITE_BACKEND_URL→https://comflex-backend.onrender.comVITE_GOOGLE_CLIENT_ID→ from Google Cloud (below)VITE_TREASURY_ADDRESS→ your EVM wallet (optional, for crypto credits)
- Deploy. The included
vercel.jsonhandles SPA routing.
- https://console.cloud.google.com → create project → APIs & Services → Credentials → OAuth client ID → Web app.
- Authorized JavaScript origins:
https://<your-app>.vercel.app(+http://localhost:5173). - Copy the Client ID into
VITE_GOOGLE_CLIENT_ID(Vercel) andGOOGLE_CLIENT_ID(Render).
- Open the Vercel URL → log in as the Seed Admin (from
SEED_ADMIN_*). - You'll land on the Setup wizard → institution name, email domain, regex. Done.
| Symptom | Fix |
|---|---|
Vercel deploys but site shows 404: NOT_FOUND |
A root vercel.json with a services block (e.g. "services": { "frontend": ... }) makes every service internal-only — nothing is routed publicly until you add top-level rewrites with destination: { "service": ... }. Simplest fix: delete the root vercel.json and set Project Settings → Root Directory = frontend, Framework = Vite, Build = npm run build, Output = dist (the frontend/vercel.json SPA rewrite stays). |
| Images broken on Vercel | Cloudinary not set on Render — uploads fell back to /tmp; add the 3 CLOUDINARY_* vars and redeploy. |
| Backend slow first click | Render sleeping → UptimeRobot should prevent this; otherwise it wakes in ~30 s. |
| Socket not connecting | VITE_BACKEND_URL must be set on Vercel (the socket uses it too now). |
| Reset link "sent" but no email | EMAIL_PROVIDER=console → read the Render logs for the link. |
| Verification/Reset mail fails ("Failed to send verification email" / 502) | Render Free Tier blocks outbound SMTP (ports 25, 465, 587). Switch to HTTPS REST API by setting EMAIL_PROVIDER=brevo and EMAIL_API_KEY=xkeysib-... (or resend with re_...). |
prisma generate fails on Render |
Nothing — just redeploy; ensure buildCommand includes npx prisma generate. |