Static-first systems for developer-facing sites

How we keep a content-heavy technical surface fast, deployable, and easy to maintain without introducing an application backend.

Workflow · Apr 18, 2026 · 4 min read

BY / Birdor Engineering · Web Systems

Updated Sep 21, 2026

Verified Sep 21, 2026

On this page · 10 sections

Problem

A developer site has different needs from a product application. It needs durable URLs, readable source content, high performance, and low operational overhead. A database and authentication layer add complexity without improving those fundamentals.

Summary

Static generation is an architectural constraint, not a temporary compromise. Content lives in version control, pages are generated from it, and deployment remains predictable.

Architecture

PLATE / MERMAID REFERENCE
flowchart TD
  Git[Git + Markdown] --> Build[Static build]
  Build --> Edge[Edge delivery]
  Edge --> Reader[Developer reader]

The content layer is intentionally plain text. A new engineering note should be a new file, not a change to a rendering component.

Implementation

At build time, discover content files, parse frontmatter, and generate a typed index. The route layer only asks for a list or a document by slug.

const pages = import.meta.glob("../content/engineering/*.md", {
  eager: true,
  query: "?raw",
  import: "default",
});

Trade-offs

Static-first does not fit personalized dashboards or real-time collaboration. It does fit a public knowledge surface where readability, resilience, and simple publishing matter more than per-user state.

How Birdor.dev actually builds

The production build is an ordered pipeline. TypeScript checks run first, followed by sitemap and RSS generation, then content validation. Vite produces browser assets; the prerender script consumes those assets to generate complete HTML documents. Finally esbuild bundles the optional Node static server. This server serves files and fallback pages; it does not render React on each request.

pnpm build
pnpm validate:internal
pnpm validate:static
pnpm validate:enhancement

Keep that order: validating generated feeds before generating them inspects old output, and prerendering before Vite can reference obsolete asset names. The script is named prerender-engineering.mjs, but it also writes home, project, Labs, author and legal documents. Changing only a React component is insufficient to update all production readers.

The shared site catalog now provides project and Labs records to both the browser and build scripts. Their detail URLs are derived for the sitemap. Editorial article relationships are validated before output is accepted. This prevents a new project entry from silently lacking a static detail page or pointing to a missing review.

The browser handoff

The initial HTML already contains a title, article or page body, and ordinary links. In main.tsx, the full stylesheet and application imports are awaited, followed by preloading the initial route. Only then does createRoot().render() replace the static root. This is a replacement render, not React hydration of the generated markup.

That distinction matters. The build template and React tree must agree on content and navigation, but they are not required to share identical component markup. The cost is maintaining two rendering paths; shared records reduce factual drift, while browser checks catch handoff failures.

If the initial application chunk or stylesheet fails before the root is replaced, the generated document remains readable. Once React has taken over, subsequent route loading uses its own visible loading state. These are different failure boundaries and should be tested separately.

A practical verification matrix

ScenarioExpected resultVerification
JavaScript disabledBody, H1 and ordinary navigation remain usableStatic browser check
Initial route download delayedGenerated body remains until the route is readyEnhancement request gate
Initial route download failsExisting static article and links remain availableEnhancement failure case
Internal navigation loads another chunkVisible loading state, then destination contentEnhancement navigation case
Article changedRSS, sitemap and static body agree with sourceFull build and internal checks
Unknown URLActual 404 document, not an invented home routeHosting/route checks

The content and catalog changes in this implementation were checked on Node 22.23.2 with pnpm 10.4.1, including no-JavaScript navigation. These checks establish local behavior. They do not measure deployed cache behavior, reader engagement or field performance. Do not turn a successful build into an unmeasured speed claim.

When this stops being enough

Personalized state and collaborative editing would need a different data boundary. Even then, a public article need not become dependent on that service. Keep the durable reading path separately testable and add interactive services only for a reader need that cannot be handled by static content.

Conclusion

Choose the smallest system that preserves the content’s usefulness. For developer-facing knowledge, that system is often a static one.