Sådan er stegger.dk bygget: En moderne SEO-stack med Astro, Cloudflare, Claude og Voyage
De fleste SEO-sites bygger jeg på WordPress. Det er sjældent det bedste valg — men det er næsten altid det pragmatiske. Når jeg byggede stegger.dk fra bunden, gav jeg mig selv lov til at droppe pragmatismen.
Resultatet er en stack med 10 værktøjer der hver løser én specifik opgave, og som arbejder sammen gennem klare interfaces. Ingen plugins der kæmper om samme DOM-element. Ingen databaser der skal caches. Ingen runtime-serverlogik der kan gå ned.
Det er ikke den rigtige stack for alle sites. Men det er en reel mulighed i 2026 — og det er den stack der giver mig mest kontrol over både SEO-arkitektur og indholdsproduktion.
Principper før værktøjer
Stacken er ikke tilfældig. Den følger fire principper der styrer hvert værktøjs-valg:
Statisk first. Indhold der ikke ændrer sig per request skal serveres statisk. Ingen databaseforespørgsler per side-visning. Ingen server-side rendering medmindre det er nødvendigt. Performance, sikkerhed og omkostning følger af dette ene valg.
Content som data. Markdown med strict frontmatter-schema er sandheden. Alt andet — editor, publiceringsflow, sitemap, structured data — er funktioner ovenpå den data.
AI som operatør, ikke forfatter. Claude Code og LLM-tools udfører specifikke opgaver i pipelinen — embeddings, klassifikation, kode-ændringer. De skriver ikke sluttekster uden menneskelig redaktionel kontrol.
Eksplicit over automatisk. Jeg foretrækker scripts jeg kan læse og forstå over plugins der gør noget i baggrunden. Validering er eksplicit (npm run validate). Embeddings-generering er eksplicit (embed.py --force). Der er ingen magi i produktionen.
Med disse fire principper i baghovedet giver resten af stacken sig selv.
Infrastruktur-laget: Git og Cloudflare Pages
Git + GitHub er source of truth. Alt indhold, al kode, alle konfigurationer versioneres. Der er ingen anden database. Når jeg committer en ny ordbogs-artikel, er det den endelige publicering — hele sitet bygges om og deployes automatisk.
Det lyder banalt indtil man sammenligner med WordPress: der eksisterer sandheden i en MySQL-database, som skal backup’es, migreres og håndteres separat fra koden. Med Git er hvert commit et komplet snapshot af sitet inklusive alt indhold.
Cloudflare Pages håndterer build og hosting. Hver push til main-branchen trigger et build af hele sitet (cirka 45 sekunder for 729 sider) og et atomic deploy til Cloudflares globale edge-netværk. Der er ingen origin-server — hele sitet lever som statiske filer i mere end 300 byer globalt.
Omkostning: 0 kroner for trafik under 500k requests/måned. For et site der ikke driver mange millioner af sidevisninger er dette effektivt gratis hosting med bedre performance end de fleste dedikerede servere ville levere.
Frontend-laget: Astro og Tailwind
Astro v5 er det framework jeg har valgt til at generere sitet. Astro er bygget specifikt til content-heavy sites: det renderer alt som statisk HTML per default, sender nul JavaScript til klienten medmindre du eksplicit beder om det, og integrerer content collections som first-class feature.
Det er astro-seo i praksis — alle sider er pre-renderet til HTML ved build-tid. Ingen rendering-kø hos Googlebot. Ingen client-side rendering-problemer. Hvad Google ser er hvad brugeren ser er hvad der er i filen.
Tailwind CSS v4 håndterer styling via @tailwindcss/vite-pluginet (ikke den gamle @astrojs/tailwind-integration). Version 4 er hurtigere, mindre konfigureret, og integrerer direkte med Vites build-pipeline. Klassernes CSS er inline-optimeret per side — ingen store utility-bundles der skal downloades.
rehype-slug er det eneste markdown-plugin jeg bruger. Det auto-genererer ID’er på alle H2-overskrifter, hvilket driver Table of Contents-komponenten og jump links-funktionaliteten. 0 JavaScript til klienten — ren HTML med anchor-links og smooth scroll via CSS.
Content-laget: Markdown og content collections
Hver ordbogs-artikel er en markdown-fil i src/content/ordbog/. Hver blog-post er en fil i src/content/blog/. Frontmatter definerer struktur: title, description, kategori, tier (pillar/sub-hub/cluster), parent, relaterede slugs, FAQ, ordantal-mål.
Astros content collections validerer denne frontmatter mod et strict schema ved build-tid. Hvis en artikel mangler tier eller har en ugyldig kategori, fejler buildet. Det fanger strukturelle fejl før de når produktion.
Fordelen ved markdown som primær content-format bliver tydelig i Claude Code-workflowet (afsnit nedenfor): LLM’er kan læse og skrive markdown natively. Der er ingen editor-API der skal kaldes. Ingen rich-text-parsing. En artikel er bare tekst — og tekst er hvad LLM’er er bedst til.
AI-laget: Claude Code som primær developer
Det her er laget hvor stegger.dk adskiller sig mest fra klassiske SEO-sites. Claude Code er ikke et værktøj jeg bruger — det er det primære miljø hvor sitet vedligeholdes.
Praktisk set betyder det: når jeg vil tilføje en ny artikel, opdatere struktur, eller implementere en feature, åbner jeg Claude Code-terminalen i projektet og beskriver hvad jeg vil. Claude læser de relevante filer, forstår sammenhængen, og udfører ændringerne — typisk direkte på filsystemet. Derefter committer jeg ændringerne.
Modellen er Claude Opus 4.6 med 1M context, som kan holde hele projektets kodebase i kontekst samtidigt. For mindre opgaver bruger jeg Sonnet (billigere, hurtigere). For analytisk tunge opgaver eller komplekse refactorings bruger jeg Opus.
Det afgørende er ikke at Claude “skriver koden”. Det er at hele arbejdsflowet — fra research til implementation til test — kan udføres i én koherent session hvor Claude har adgang til både kodebasen, dokumentationen (CLAUDE.md) og tool-suiten (scripts, validators, embeddings).
OpenRouter + flux.2-flex håndterer hero image-generering for blog-posts og pillar-artikler. scripts/generate-hero-images.mjs læser image-prompts.json hvor hver artikel har en defineret visuel vinkel og master prompt, kalder OpenRouters API, og gemmer resultatet som hero.jpg i src/assets/blog/<slug>/. Frontmatter opdateres automatisk. Cost per image: cirka 0,40 kr.
Semantik-laget: Voyage AI og den lokale analyzer
Det her er det lag jeg er mest glad for. Hele stegger.dk’s interne struktur — hvilke artikler linker til hvilke, hvilke hubs indeholder hvilke clusters, hvilke gaps der findes — er valideret mod Voyage AI’s voyage-3-large embedding-model i 2048 dimensioner.
scripts/semantic-analyzer/ indeholder en suite af analyse-scripts:
- embed.py — embedder alle 693 artikler via Voyage API (eller lokal
sentence-transformerssom fallback). Cacher embeddings idata/embeddings/baseret på content-hash. Re-embedder kun artikler der har ændret sig. - analyze.py — dedup-detection (find artikler med >0.85 cosine similarity), orphan-detection (clusters med svag semantisk forbindelse til parent), related-forslag (cross-hub link-kandidater).
- analyze.py suggest “emne” — pre-write check før nye artikler skrives. Returnerer dedup-risiko, foreslået parent hub, og de bedste cross-hub relaterede.
- node-coverage.py — tagger clusters som attribute/problem/method/comparative og flagger hubs der mangler et Koray-krævet lag.
- content-gap-centroid.py — centroid-baseret analyse: for hver hub, find eksterne artikler tæt på hub-centroid som ikke er linket endnu.
- query-fanout.py — genererer 18 LLM-query-varianter per hub og tjekker om ordbogen har stærke matches. Koray 13.4 i automatiseret form.
Omkostning for en fuld re-embed af hele sitet via voyage-3-large: cirka 1 krone. Analyserne er gratis fordi de kører på cachede embeddings.
Den konkrete værdi: hver ny artikel gennemgår pre-write check før den skrives. Det fanger dedup-risici og foreslår korrekt placering. Efter publicering kan reverse-backlink-analyse finde blog-indlæg der burde linke til den nye artikel. Alt sammen bygget på samme Voyage-embedding-basis.
SEO-operationel-laget: NeuronWriter og GSC
NeuronWriter håndterer keyword research for pillar- og sub-hub-artikler. scripts/nw-create-queries.py opretter queries for hvert relevant slug via NeuronWriters API. Data er grundlag for content briefs, men cluster-artikler får ikke queries — det er overkill for niche-long-tail content.
Google Search Console er primær datakilde for performance-analyse. Der er ingen tredjeparts rank tracker i løbende brug — GSC er autoritativ kilde for impressions, CTR og gennemsnitsposition. Ahrefs bruges ad hoc til konkurrent- og backlink-analyse, ikke til daglig tracking.
validate.cjs er det script der holder det hele sammen. Det checker: brudte relaterede-slugs, brudte parent-referencer, hierarki-fejl (cluster må ikke pege direkte på pillar), for få/mange relaterede (4-8-reglen), FAQ-minimum (5 for hubs, 3 for clusters), brudte inline ordbog-links, short content og ensrettede link-relationer. Kører som npm run validate før hver commit — returnerer exit 1 hvis der er fejl.
Publishing-laget: IndexNow og structured data
IndexNow sender crawl-notifikationer til Bing og Yandex ved hver deployment via astro-indexnow-pluginet. Det reducerer crawl-delay for nyt indhold i ikke-Google søgemaskiner markant. Google bruger ikke IndexNow, men ChatGPT Search, Copilot og andre Bing-baserede AI-systemer gør.
JSON-LD structured data genereres på tværs af sitet via Astro-komponenter. Hver sidetype har sit eget schema:
- Ordbogs-artikler: DefinedTerm (individuel) + DefinedTermSet (oversigtsside) + BreadcrumbList + FAQPage + SpeakableSpecification (for pillars/sub-hubs).
- Blog-posts: NewsArticle + Person (forfatter) + BreadcrumbList + FAQPage hvis relevant.
- About-siden: Person med
sameAs,worksFor,knowsAbout. - Pillar- og sub-hub-artikler plus lange blog-posts: SiteNavigationElement for Table of Contents (fremmer potentielle sitelinks).
- Forsiden og globalt: WebSite med søgeboks-markup.
Alle schemas valideres via Schema.org Validator inden deploy. Broken JSON-LD ignoreres helt af Google — det er billig forsikring mod at miste rich results.
Konkret workflow: fra idé til publiceret artikel
Sådan ser en typisk content-produktion ud når alle lag arbejder sammen:
- Idé — et emne identificeres via GSC-data (impressions uden klik), query fan-out-analyse (ordbog-gap), eller centroid-analyse (hub der mangler problem-node).
- Pre-write check —
analyze.py suggest "emne-beskrivelse". Returnerer dedup-risiko, foreslået parent, og top 8 relaterede. Hvis dedup > 0.85, skrives ikke — eksisterende artikel udvides i stedet. - Brief — jeg skriver et kort content brief (ofte i samme Claude Code-session) med H2-struktur, node-type, kanonisk term fra pillar-artiklen.
- Førstekast — skrives enten manuelt eller AI-assisteret afhængigt af emne. For tekniske emner med dyb erfaring skriver jeg det selv. For breddere konceptuelle emner bruger Claude som førstekast som jeg derefter redigerer og tilføjer original indsigt.
- Frontmatter + relaterede — baseret på pre-write check, men manuelt justeret til 4-8 links med fokus på cross-hub relationer.
- Validering —
npm run validate. Fejler hvis struktur eller links er brudt. - Build-test —
npm run buildlokalt for at fange Astro-specifikke fejl. - Commit + push — Cloudflare Pages builder og deployer automatisk. IndexNow notificerer Bing.
- Post-publish enrichment —
analyze.py suggestopdateres,apply-blog-links.pykan foreslå nye inline-links fra ældre posts til den nye artikel.
Hele processen for en cluster-artikel tager typisk 2-4 timer. For en sub-hub eller pillar tager det længere — både fordi artiklerne er større og fordi deres strukturelle rolle kræver mere omhyggelig placering.
Hvad jeg har droppet
Lige så vigtigt som hvad stacken indeholder er hvad den IKKE indeholder:
WordPress — droppet fordi plugin-økosystemet skaber løbende teknisk gæld, Core Web Vitals-performance er vanskelig uden omhyggelig optimering, og fordi hele redaktionelle fordelen forsvinder når Claude Code er den primære content-editor alligevel.
Webflow/Framer — droppet fordi content-portabilitet er dårlig, structured data-kontrol er begrænset, og fordi SEO-teknisk dybde er vanskelig at opnå uden at kæmpe mod platformens defaults.
Headless CMS (Sanity, Contentful) — overvejet og fravalgt. Ville give bedre editor-UI, men tilføjer en ekstra afhængighed og et ekstra API der skal opretholdes. For et enkelt-persons-site hvor Claude Code er primær editor er det unødvendig kompleksitet.
Databaser — der er ingen. Alt indhold er markdown i Git. Alt analytisk data er JSON-filer i data/-mappen. Ingen runtime-queries, ingen caching-lag, ingen backup-strategi nødvendig ud over git push.
Tredjeparts analytics og tracking — der er ingen Google Analytics, ingen heatmaps, ingen conversion-tracking. GSC giver den data jeg har brug for. Mindre cookie-banner-tvang, mindre tredjeparts-scripts, bedre performance.
Tal og resultater
Efter 3 måneders drift med denne stack:
- 693 ordbogs-artikler plus 30 blog-posts i produktion
- 729 total sider i sitemappet (inklusive pillars, blog, forside, om-siden)
- 0 runtime fejl i production — statisk hosting kan ikke crashe
- ~45 sekunder build-tid for hele sitet via Cloudflare Pages
- 0,08 USD per fuld Voyage re-embed af alle 693 artikler (kører manuelt 1-2 gange om måneden)
- 4305 interne relaterede-links fordelt på 4-8 per artikel, middelværdig cosine similarity 0.78 (valideret af Voyage)
- 0 fejl i
npm run validatevedvarende — struktur og links holdes rene gennem automatiseret CI-gating
Sitet har ikke akkumuleret lang organisk trafikhistorik endnu. Resultaterne her er strukturelle, ikke ranking-baserede — topical authority tager 6-12 måneder at materialisere sig i trafik.
Tool-valg er tidsbundet, principper er ikke
Stacken ser ud som den gør i april 2026 fordi Voyage-3-large er den bedste danske multilingual embedding-model lige nu, fordi Cloudflare Pages er den bedste gratis statiske hosting, og fordi Claude Opus 4.6 er den mest kompetente coding-agent. Alt det kan ændre sig inden for 12 måneder.
Men principperne ændrer sig ikke: statisk first, content som data, AI som operatør, eksplicit over automatisk.
Hvis du bygger et lignende site i 2027 med andre værktøjer — en ny embedding-leverandør, et nyt statisk framework, en ny AI-agent — vil arkitekturen sandsynligvis se næsten identisk ud. Værktøjerne er udskiftelige. Valgene om hvordan de hænger sammen er ikke.
Det er den virkelige lektie fra at bygge stegger.dk på denne stack: tool-valg er mindre interessant end arkitektur-beslutninger. De fleste SEO-sites skal bruge 3-6 måneder på at vælge værktøjer — og derefter opdage at de grundlæggende problemer var strukturelle, ikke tekniske.