When you deploy a frontend or a web app on Render, you’re picking between two service shapes:
- A static site - pre-built files served from Render’s global CDN. No process, no port, no server-side code at runtime.
- A web service - a long-running process (Node, Python, Go, Rust, Docker, …) listening on a port. Render’s edge proxies traffic to it.
The whole tutorial collapses to one question.
Before you start
This tutorial is decision-focused, so you don’t need to deploy anything to follow along. To actually ship one of the patterns at the end, you’ll want:
- A Render account. The free tier covers static sites and small web services.
- A frontend or web app to deploy. Any project you can
git pushto GitHub, GitLab, or Bitbucket works. - Comfort reading a
render.yamlsnippet. The Blueprint examples in steps 2 to 5 are short.
The static sites docs and web services docs are good companions if you want to read the platform’s full surface as you go.
The decisive question
Does my code need to run on a server to respond to a request?
If yes → web service. If no → static site. That’s it.
flowchart TB q["Does code need to run<br/>per-request on a server?"] yes["Yes:<br/>API, SSR, websockets,<br/>auth, DB queries"] no["No:<br/>HTML/CSS/JS bundle,<br/>built once, served from CDN"] ws["Web service"] ss["Static site"] q -->|"yes"| yes q -->|"no"| no yes --> ws no --> ss
A few examples to anchor it:
| What you’re shipping | Pick | Why |
|---|---|---|
| React/Vue/Svelte SPA | Static site | Built once, runs in the user’s browser |
| Marketing site, blog, docs (Hugo, Docusaurus, Jekyll) | Static site | No server-side logic at runtime |
Next.js with next export / output: 'export' | Static site | Framework produces static files |
Next.js with next start (full SSR) | Web service | Server renders pages per request |
| Express, FastAPI, Rails, Django, Go HTTP server | Web service | A long-running process serves traffic |
| WebSocket server, real-time backend | Web service | Persistent connection requires a process |
| Astro with no SSR adapter | Static site | Output is HTML files |
| Astro with Node adapter | Web service | The adapter runs a Node process |
The middle two are where teams get tripped up. The framework name doesn’t decide - its output shape does. Run your build locally and look at what’s in the publish folder. If it’s HTML/CSS/JS files you could open in a browser without a server, you have a static site.
The full comparison
| Dimension | Static site | Web service |
|---|---|---|
| What runs at request time | Nothing - the CDN serves built files | Your process |
| Free tier | Yes, with bandwidth and build minutes | Yes, but services spin down on inactivity |
| Cold starts | None - CDN is always warm | Yes on free tier (first request after idle) |
| Custom domains | Yes, on free tier too | Yes, but not on free instance type |
| Private network | No - can’t talk to other services internally | Yes - can reach pserv, KV, Postgres |
| Persistent disks | No | Yes |
| Scaling | Global CDN, unlimited concurrent reads | Manual or autoscaling instances |
| TLS | Auto-provisioned, free | Auto-provisioned, free, terminates at edge |
| PR previews | Yes | Yes |
| Build artifact | Folder of files (dist, build, public) | Runnable process or container |
| Cost shape | Bandwidth + build minutes | Instance hours + bandwidth |
A few of those rows decide cases on their own:
- No private network on static sites. A static site cannot call your
pservoverauth.onrender.com-style internal hostnames. It has to call the public URL. We dig into the workaround in the hybrid pattern step. - Free static sites get custom domains; free web services don’t. If you want
mysite.comfor free, ship it as a static site (or move the web service to a paid plan). - Static sites don’t sleep. A free web service spins down after 15 minutes of inactivity and cold-starts on the next request. Static sites never sleep - the CDN is always warm.
When you genuinely need both
Most real apps end up shipping both: a static site for the frontend, a web service for the API. That’s the right answer when:
- Your frontend is a SPA (React, Vue, etc.) and you have a backend with auth, DB queries, or third-party integrations.
- You want to take advantage of the free CDN for the frontend without giving up server logic for the backend.
- You want to scale the frontend (free, infinite) and the backend (sized for actual load) independently.
We cover the wiring in step 04. For now, the takeaway: picking one doesn’t lock the other out. Two services in one Blueprint is the most common shape for a serious app.
What this tutorial walks you through
flowchart LR s1[01 the decision] s2[02 static sites] s3[03 web services] s4[04 hybrid pattern] s5[05 migration paths] s1 --> s2 --> s3 --> s4 --> s5
Steps 02 and 03 are the focused chapters for each service type. Step 04 covers the most common production shape. Step 05 covers what happens when you outgrow your initial choice.
What you learned
- The decisive question: 'does my code need to run on a server to respond to a request?'
- Most SPAs, marketing sites, docs, and blogs are static sites. APIs, SSR, websockets, and anything with persistent connections are web services
- Static sites have a free CDN, free custom domains, no cold starts - but no access to Render's private network
- Web services can talk to internal services and use disks, but free-tier services sleep on inactivity and don't get custom domains
- Real apps often ship both: static frontend + web service API in the same Blueprint