“Just use a static site generator” is advice that sounds clean until you need search, auth, or anything that changes without a deploy.
The hidden costs
Static does not mean zero infrastructure. You still need hosting, CDN configuration, preview environments, and a build pipeline that runs on every content change.
“There is no cloud. It’s just someone else’s computer.” — Unknown
Astro, Eleventy, and Hugo all shift complexity left — they do not eliminate it.
Build pipeline in practice
Even a “simple” blog has a CI graph:
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
- run: bun install --frozen-lockfile
- run: bun run build
- uses: actions/upload-pages-artifact@v3
with:
path: apps/web/distThat’s four moving parts before a single visitor hits your homepage. The bill moved from runtime to build time — it didn’t disappear.
Where static wins
Content that changes rarely and is read by many:
- Blogs and personal sites
- High read-to-write ratio
- CDN cache hits are nearly free
- Documentation
- Versioned with git
- Preview deploys per PR
- Marketing pages
- No auth, no personalization
- Ship once, serve forever
Where static loses
Personalized dashboards, real-time data, user-generated content. Fighting the model costs more than adopting a server. Know which side of the line you are on before you commit.
// This does not belong in SSG — it needs a server
export async function GET({ cookies }) {
const session = cookies.get("session");
if (!session) return new Response(null, { status: 401 });
const user = await db.user.find(session.value);
return Response.json(user.preferences);
}If you’re writing handlers like that, you’ve already left static territory.