SaaS Dev9 min read · 5 April 2026

Deploying a Full-Stack SaaS for Free: Supabase + Render + Vercel

How I deployed CanopyCare — a production Node.js + React booking system — at zero monthly cost using Supabase for PostgreSQL, Render for the backend, Vercel for the frontend, and Cloudflare for the custom subdomain.

DeploymentSupabaseRenderVercelCloudflareNode.jsDevOps

The Zero-Cost Stack

When I deployed CanopyCare — a full booking SaaS with auth, photo uploads, email notifications, and an admin panel — I did it without spending a penny. Here's the exact stack:

ServicePurposeFree Tier
SupabasePostgreSQL DB500MB, 50K MAU
RenderNode.js backend750 hrs/month
VercelReact frontendUnlimited deploys
CloudflareSubdomain DNSFree
CloudinaryPhoto storage25GB
ResendTransactional email3K/month

Step 1 — Database: Supabase

Supabase gives you a full PostgreSQL database with a connection string you can use directly with Prisma:

bash
# .env
DATABASE_URL="postgresql://postgres.xxxx:password@aws-eu-west-1.pooler.supabase.com:5432/postgres"
DIRECT_URL="postgresql://postgres.xxxx:password@aws-eu-west-1.pooler.supabase.com:5432/postgres"
prisma
// schema.prisma
datasource db {
  provider  = "postgresql"
  url       = env("DATABASE_URL")
  directUrl = env("DIRECT_URL")
}

Run migrations pointing directly at Supabase:

bash
DATABASE_URL="your_supabase_url" npx prisma migrate deploy

Step 2 — Backend: Render

Render auto-detects Node.js. The key settings:

  • Build command: npm install && npx prisma generate
  • Start command: node src/server.js
  • Instance type: Free

Critical: move prisma from devDependencies to dependencies — Render's production build skips dev deps:

bash
npm install prisma --save
git add package.json && git commit -m "fix: prisma to dependencies" && git push

Your backend will be live at https://your-app.onrender.com. Note: free tier spins down after 15 mins of inactivity — first request takes ~30s to wake up.

Step 3 — Frontend: Vercel

Vercel auto-detects Vite. Add one environment variable:

VITE_API_URL = https://your-backend.onrender.com/api

For client-side routing (React Router), add a vercel.json at the root:

json
{"rewrites":[{"source":"/(.*)", "destination":"/index.html"}]}

Without this, direct URL access to /register, /dashboard etc. returns 404.

Step 4 — Custom Domain: Cloudflare Subdomain

If you own a domain on Cloudflare, you can create a free subdomain pointing to Vercel:

Type: CNAME
Name: canopycare
Value: [your-vercel-cname].vercel-dns.com
Proxy: OFF (grey cloud)

Then add the subdomain in Vercel → Settings → Domains.

CORS Configuration

The most common production bug: your backend CORS only allows the Vercel URL but you've added a custom domain. Always keep FRONTEND_URL updated on Render:

javascript
// app.js
app.use(cors({
  origin: process.env.FRONTEND_URL,
  credentials: true,
}))

Total Monthly Cost: £0

The entire CanopyCare stack — database, backend API, frontend, photo storage, email — runs completely free. For a portfolio project or early-stage startup, this is all you need.

MH
Mahmudul Hassan Mithun
AI SaaS Builder · BSc Data Science & AI, UEL · Building ContentForge AI

Related Posts

Multi-Tenant SaaS Architecture with Next.js 15, Prisma & Auth0
Multi-Tenant SaaS Architecture with Next.js 15, Prisma & Auth0
15 min read →
Deploying FastAPI to Railway: The Production Checklist
Deploying FastAPI to Railway: The Production Checklist
8 min read →