Netlify is one of the fastest ways to get a frontend from a Git repo to a global CDN with HTTPS, previews, and serverless functions — and for static sites and JAMstack apps it's genuinely hard to beat on setup time. But the parts that make it effortless at the start (opinionated build pipeline, bundled functions, generous-but-metered free tier) are the same parts that bite you at scale or when your app stops looking like a static site. This post is what I've learned actually shipping on it: where it shines, where it hurts, and concrete config for both.
What is Netlify actually good at?
At its core Netlify does one thing extremely well: it takes a Git push, runs your build command, and atomically deploys the output to a CDN. Every deploy is immutable and instantly rollback-able. You connect a repo, set a build command and a publish directory, and you're live.
The parts I lean on most:
- Deploy previews per pull request. Every PR gets its own URL. For design review and QA this alone justifies the tool — reviewers stop asking "can you push it somewhere I can click?"
- Atomic deploys and one-click rollback. A bad deploy never leaves you half-updated, and reverting is instant because the previous build still exists on the CDN.
- Netlify Functions (AWS Lambda under the hood) for small backend needs — form handlers, webhook receivers, a thin API — without provisioning anything.
-
Redirects and headers as code via a
netlify.tomlor_redirectsfile that lives in your repo, so routing is reviewable in PRs instead of clicked into a dashboard.
A minimal netlify.toml covers most of what a small site needs:
[build]
command = "npm run build"
publish = "dist"
# SPA fallback: serve index.html for client-side routes
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[[headers]]
for = "/assets/*"
[headers.values]
Cache-Control = "public, max-age=31536000, immutable"
The takeaway: for a static site or SPA, Netlify gets you to a production-grade setup — CDN, HTTPS, previews, cache headers — in the time it takes to write that file.
When is Netlify the right choice?
Netlify is the strong default when your project matches its shape. Concretely:
- Marketing sites, docs, blogs, and landing pages. Static output, occasional form submissions, no persistent server. This is the home-run case.
- SPAs and JAMstack apps (React/Vue/Svelte/Astro) where the backend is a handful of API calls to third parties or a few functions.
- Client and side projects where velocity matters more than infra control. You want previews and rollbacks without owning a pipeline.
A common concrete pattern: a static contact form with zero backend code. Netlify Forms detects a form at build time if you tag it, and captures submissions server-side:
<form name="contact" method="POST" data-netlify="true">
<input type="hidden" name="form-name" value="contact" />
<input type="text" name="name" required />
<input type="email" name="email" required />
<textarea name="message"></textarea>
<button type="submit">Send</button>
</form>
No function, no database, no server. Submissions show up in the dashboard and can trigger notifications. For a small site that's a real amount of backend you didn't have to build — though note Netlify Forms has its own submission quota on the free tier, so it's not free-forever at volume.
The takeaway: if your app is static-plus-a-little, Netlify removes an entire category of infrastructure work.
What are Netlify's real drawbacks?
This is where honesty matters, because the friction is real and predictable.
Build minutes and bandwidth are metered, and overages surprise people. The free tier includes a fixed pool of build minutes and bandwidth per month (the exact figures have changed over time — check the current pricing page rather than trusting a number in a blog post). Heavy CI on a monorepo, or a site that gets a traffic spike, can push you into paid territory or throttling faster than you'd expect. Long builds are the sneaky one: a slow build eats minutes on every PR and every merge.
It's opinionated about the build. Netlify runs your build in its own environment. When a build passes locally but fails on Netlify, it's usually a Node version mismatch, a missing environment variable, or a native dependency that isn't in their image. Pin your Node version explicitly to cut down on this class of bug:
[build.environment]
NODE_VERSION = "20"
Functions are fine until they aren't. Netlify Functions are great for lightweight, stateless work, but they inherit Lambda's constraints — cold starts, execution time limits, and payload size limits. If you find yourself fighting timeouts, long-running jobs, or wanting persistent connections (WebSockets, a long-lived DB pool), you're using the wrong tool. Netlify has edge functions and background functions to stretch this, but a genuine always-on backend belongs on a container platform, not here.
Vendor-specific features create lock-in. Netlify Forms, Identity, and the redirect/header syntax are convenient but proprietary. The static output is portable; the platform glue around it is not. The more you lean on the extras, the more a migration costs later.
The takeaway: Netlify optimizes for the static-and-a-little case, and every drawback is a version of "you asked it to be a full application server, and it isn't one."
Netlify vs. the alternatives at a glance
| Need | Netlify | When to look elsewhere |
|---|---|---|
| Static site / SPA / docs | Excellent fit | — |
| Deploy previews per PR | First-class | — |
| Light serverless (forms, webhooks) | Good | Heavy/long-running jobs → container host |
| Next.js / heavy SSR framework | Works, but framework-specific hosts optimize harder | Framework's native host may deploy more smoothly |
| Always-on backend, WebSockets, DB pool | Not the right layer | Container/VM platforms (Fly.io, Render, Railway) |
| Predictable cost under traffic spikes | Metered; watch overages | Fixed-price VMs if traffic is heavy and steady |
Treat this as a starting map, not gospel — the frontier moves, and both Netlify and its competitors ship features every quarter. The takeaway: match the tool to the shape of your app, not to its logo.
How do you avoid the common Netlify mistakes?
A few habits save most of the pain:
-
Pin your Node/tooling versions in
netlify.tomlso local and CI builds match. The most common "works on my machine" failure disappears once you do. - Watch build time from day one. Cache dependencies, avoid rebuilding untouched packages in a monorepo, and skip builds for docs-only commits. Minutes are the resource you'll hit first.
- Keep functions stateless and short. If a function wants a persistent connection or runs for many seconds, that's a signal to move it off Netlify, not to tune it harder.
-
Set explicit cache headers for hashed assets (
immutable, long max-age) and short/no cache for HTML, so the CDN works for you instead of serving stale pages.
The takeaway: Netlify rewards treating configuration as code and punishes leaning on it as an application server.
Bottom line
If you're shipping a static site, a docs portal, a marketing page, or an SPA with a light backend, Netlify is one of the best-in-class choices and you should probably just use it — the previews and rollbacks alone pay for themselves. If your project has a real always-on backend, WebSockets, long-running jobs, or heavy predictable traffic, Netlify will fight you, and a container platform is the honest answer. And whatever tier you're on, watch build minutes and bandwidth early — the overage, not the setup, is what surprises people. Pick it for the shape of your app, and don't lean on the proprietary extras any harder than you're willing to migrate off later.
Top comments (0)