What a static site gives up, and what it gets

This blog has no server, no database and no login. Here is what that costs and why I chose it anyway.

Sample post. Replace it with your own writing.

Every page on this site is a file that was written once, when I ran a build. Nothing is computed when you ask for it. That one decision shaped everything else, so it is worth being precise about the trade.

Build time, not request time

A dynamic site assembles each page when a visitor requests it. A static site assembles every page ahead of time and then hands out files. Running astro build is the only moment any of my code executes.

  1. Markdown files go in.
  2. One build step runs.
  3. Static HTML comes out.

What it gives up

  • Anything personal to the reader: accounts, comments, saved state.
  • Instant publishing. A new post means a commit and a rebuild.
  • Content that changes without a deploy.

What it gets

Fewer moving parts. There is no server to patch and no database to back up, and a broken post fails the build instead of breaking the live site. The check lives in one small schema:

const posts = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/content/posts' }),
  schema: z.object({
    title: z.string().min(1),
    pubDate: z.coerce.date(),
    tags: z.array(z.string()).default([]),
    visibility: z.enum(['public', 'private']).default('private'),
  }),
});

If a post is missing its title, the build stops. The schema is the boundary: once data is past it, the rest of the code can trust it.

The rule I took from this: pick the simplest architecture the content actually needs, and write down what would make you change your mind.

The next post covers validating data at the boundary in more detail.