Best Static Site Generator Stack for a 178-Page Obsidian Wiki
Executive Summary
For converting a 178-page Obsidian-style Markdown wiki with [[wiki links]], YAML frontmatter, and subdirectory organisation into a read-only HTML knowledge base for a single non-technical user, the recommended stack is:
Quartz v4 (SSG) + FlexSearch (built-in search) + Cloudflare Pages (hosting) + Cloudflare Access with email OTP (access control)
This combination provides the lowest setup effort, zero ongoing maintenance cost, native Obsidian compatibility without plugins, and auto-deploy on git push — all on free tiers. Quartz is the only SSG evaluated that handles [[wiki links]] out of the box with zero configuration, which eliminates the single largest source of integration risk.
A strong runner-up stack — Starlight (Astro docs theme) + Pagefind (search) + Cloudflare Pages + Cloudflare Access — offers better long-term maintainability and search quality, but requires the starlight-obsidian plugin and more initial configuration.
Static Site Generator Comparison
Summary Matrix
| Criterion | Quartz v4 | MkDocs Material | Docusaurus | Astro (bare) | Starlight (Astro) | Eleventy | Hugo | VitePress |
|---|---|---|---|---|---|---|---|---|
| Wiki links native | Yes | No (plugin) | No (plugin) | No (plugin) | No (plugin) | No (plugin) | No (custom Go) | No (plugin) |
| Frontmatter parsing | Yes | Yes | Yes (MDX) | Yes | Yes + schema | Yes | Yes | Yes |
| Build ~200 pages | ~5–15s | ~3s | ~15–30s | ~5–15s | ~5–12s | ~0.5s | ~0.1–0.3s | ~3–5s |
| Theme quality (wiki) | Best | Excellent | Good | DIY | Excellent | DIY | Theme-dependent | Good |
| Plugin ecosystem | 27 built-in | Large (Python) | Large (React) | Large (remark) | 42 focused | 100+ npm | 189 themes | Moderate |
| Maintenance risk | Single maintainer | Maintenance mode | Meta-backed | Venture-backed | Astro org | Single maintainer | Very active | Vue.js org |
| Setup for this use case | ~15–30 min | ~45–60 min | ~2–4 hrs | ~2–3 hrs | ~1–2 hrs | ~2–3 hrs | ~3–4 hrs | ~1–2 hrs |
| GitHub stars | 11.8K | 26.5K | 64.5K | 58.4K | 8.3K | 19.5K | 87.5K | 17.5K |
| Latest release | v5.0.0 tag (active dev on v4 branch, Mar 2026) | 9.7.6 (Mar 2026) | Active | Active (daily) | 0.38.3 (Apr 2026) | 3.1.5 (Mar 2026) | 0.160.1 (Apr 2026) | 2.0.0-alpha.17 |
Detailed Evaluations
Quartz v4
Quartz is the only SSG purpose-built for Obsidian vaults (Quartz documentation). Wiki link resolution is handled natively by the CrawlLinks plugin with zero configuration. It supports all three Obsidian link resolution modes — shortest path, relative, and absolute — controlled via markdownLinkResolution in quartz.config.ts (Quartz wikilinks docs). Heading anchors ([[Page#section|Section]]), block references ([[Page#^block-id|^block-id]]), aliases ([[Page|Display Text]]), and transclusion embeds (![[Page]]) all work natively.
The default theme ships a graph view, backlinks panel, popover previews, table of contents, explorer sidebar, and full-text search — all the elements expected in a knowledge base, with no additional configuration (Quartz configuration docs). Search is powered by FlexSearch, which returns results in under 10ms for sites up to half a million words and includes a Cmd+K / Ctrl+K modal with highlighted excerpts (Quartz search docs).
The main risks are maintainability and edge case handling. Quartz is maintained by a single developer (jackyzha0) with 11.8K GitHub stars — a bus factor of 1. There is a known case-sensitivity bug where [[Note Two]] vs [[Note two]] silently produces a 404. Broken wiki links generate no build-time warning — they silently become dead links in the output. Performance can degrade on default settings due to the graph view component inflating JavaScript bundle size from 60KB to 618KB; disabling the graph view and Mermaid restores mobile PageSpeed from 34 to 91.
MkDocs Material
MkDocs Material has the most polished documentation theme of any SSG (26.5K stars), with excellent search, dark mode, versioning, and navigation. Build time for 200 pages is roughly 3 seconds — among the fastest. However, wiki link support requires the third-party mkdocs-obsidian-links (ezlinks) plugin, which adds warn_ambiguities: true for disambiguation and a CSS class for broken links.
The critical concern is ecosystem health. MkDocs Material entered maintenance mode in November 2025, with the maintainer building a successor product (Zensical). MkDocs core has had no meaningful development in 18+ months. Starting a new project on a platform in maintenance mode introduces risk that bugs and compatibility issues will go unresolved. The Python ecosystem requirement (pip, virtualenv) adds friction compared to Node.js-based alternatives.
Docusaurus v3
Maintained by Meta with 64.5K GitHub stars, Docusaurus has the strongest organisational backing of any option. It ships the best built-in broken link checker (configurable to halt builds on broken links). However, it is the worst fit for Obsidian content: there is no mature wiki link plugin (the best available, docusaurus-plugin-obsidian-vault, has 1 star and 2 commits). MDX strictness means many Obsidian Markdown patterns require manual fixing. Build times of 15–30 seconds reflect the React/MDX overhead. Setup time is estimated at 2–4 hours, making it the most labour-intensive option for this use case.
Starlight (Astro Docs Theme)
Starlight is an Astro-native docs framework with 8.3K stars and backing from the Astro organisation (used by Cloudflare, Google, and Microsoft for their docs). It ships Pagefind as its default search engine with zero configuration, provides sidebar navigation, dark mode, and mobile responsiveness out of the box.
The starlight-obsidian plugin (134 stars, last release March 2026) handles wiki link resolution, heading anchors, and embeds. Additional community plugins include starlight-links-validator for build-time broken link detection and starlight-site-graph for an Obsidian-style node graph. TypeScript frontmatter schema validation means invalid frontmatter produces clear build errors rather than silent failures.
The trade-off is that the Obsidian plugin is a single-person project (134 stars vs Quartz’s native support), and setup requires ~1–2 hours versus Quartz’s 15–30 minutes. Build time for 200 pages is 5–12 seconds.
Eleventy (11ty)
Eleventy offers the best broken link handling of any SSG via @photogabble/eleventy-plugin-interlinker, which provides console warnings, JSON reports for CI, and configurable severity. It enforces alias uniqueness (build halts on duplicate aliases). Build time is fast (~0.5 seconds for 200 pages).
The major drawback is that Eleventy ships no default theme — building a knowledge base layout from scratch or adapting a starter template is a multi-hour effort. The project is maintained by a single developer (Zach Leatherman, 19.5K stars), creating the same bus-factor risk as Quartz. Wiki link support is good but not as complete as Quartz’s native Obsidian compatibility (no block references, no transclusion).
Hugo
Hugo is the fastest SSG by a wide margin — 200 pages build in 0.1–0.3 seconds thanks to its Go-based compiler (Hugo GitHub, 87.5K stars). It has the most active maintenance cadence with monthly releases. However, its lead maintainer explicitly closed the native wiki link feature request in May 2023, stating [[...]] syntax makes Markdown “unportable.” Wiki link support requires ~100 lines of custom Go template code that you write and maintain yourself. Hugo’s urlize function aggressively strips special characters (&, ?, !) from URL slugs, which can cause silent URL collisions between pages with similar names. Not recommended for this use case unless Hugo is already in use for other reasons.
VitePress
VitePress (17.5K stars) provides an excellent docs theme with Vue.js integration. Wiki links are handled via the @portaljs/remark-wiki-link package, which supports heading anchors and display text. MiniSearch is the built-in search engine with true Levenshtein fuzzy matching.
The concern is maturity: VitePress is still in v2.0.0-alpha, with potential breaking changes ahead. Its wiki link resolution relies on a permalinks array that must be regenerated when content changes — case-sensitive exact string matching with no built-in ambiguity detection.
Client-Side Search Comparison
Summary Matrix
| Criterion | Pagefind | Lunr.js | FlexSearch | MiniSearch | Fuse.js | Stork | Algolia DocSearch |
|---|---|---|---|---|---|---|---|
| Index size (200 pages) | ~100–150 KB chunked | ~500 KB–1 MB | ~300–600 KB | ~300–500 KB | ~200–500 KB | Varies (.st binary) | Hosted |
| On-demand loading | Chunked (partial) | Full load | Full load | Full load | Full load | WASM + partial | API calls |
| Ranking | BM25-inspired, tunable | BM25F | Contextual (custom) | BM25+ | IDF-weighted Bitap | Custom | Proprietary |
| Typo tolerance | Prefix/stemming only | Manual ~1 syntax | Phonetic/tokenizer | Levenshtein (configurable) | Bitap (≤32 chars) | Prefix only | Full automatic |
| Ships a UI | Full modal + excerpts | API only | API only | API only | API only | Input + overlay | Full ⌘K modal |
| Stars / Last release | 5.1K / Apr 2026 | 9.2K / 2019 | 13.7K / May 2025 | 5.9K / 2025 | 20.1K / Apr 2026 | 2.8K / Jan 2023 | SaaS |
Analysis
Pagefind is the strongest overall choice for static knowledge bases (pagefind.app). Its chunked index loading means the browser only downloads the slice relevant to each query — roughly 100–150 KB total for a 200-page site, with only a fraction loaded per search. It ships a complete drop-in UI with excerpts, sub-results by heading, and highlighting. It works with any SSG as a post-build step and is Starlight’s built-in default. Its main weakness is the absence of true Levenshtein fuzzy matching — it relies on stemming and prefix matching, so a search for “astor” will not find “astro.”
MiniSearch offers the best typo tolerance of the client-side options, with configurable Levenshtein distance matching (fuzzy: 0.2) and BM25+ ranking (MiniSearch GitHub). It ships no UI components, but VitePress bundles it with a polished modal interface. The full index for 200 pages loads in one shot (~300–500 KB raw, ~60–100 KB gzipped) — acceptable at this scale.
FlexSearch is what Quartz uses natively. It is extremely fast (sub-10ms for half a million words) and supports CJK tokenisation, but does not implement true Levenshtein fuzzy matching despite marketing claims — its “fuzzy” is tokenizer/phonetic-based (Quartz search docs).
Lunr.js is unmaintained (last release 2019) and should be avoided for new projects. It remains MkDocs Material’s default, but the Material maintainer has acknowledged its BM25 implementation is poorly suited to typeahead search.
Fuse.js (20.1K stars) excels at fuzzy matching short strings (titles, names) but performs a linear scan per query — unsuitable for full-text paragraph search across 200 pages.
Stork is abandoned (developer wound down the project; last release January 2023). Do not use for new work.
Algolia DocSearch is best-in-class on every dimension (typo tolerance, ranking, UI, ⌘K modal) but the free tier requires the site to be publicly accessible open-source documentation. A private business knowledge base does not qualify.
SSG-Search Integration Map
| SSG | Built-in Search | Integration Effort |
|---|---|---|
| Quartz | FlexSearch (built-in, zero config) | None |
| Starlight | Pagefind (built-in, zero config) | None |
| VitePress | MiniSearch (built-in, zero config) | None |
| MkDocs Material | Lunr.js (built-in, legacy) | None (but Lunr is unmaintained) |
| Hugo | None | Post-build Pagefind step |
| Eleventy | None | Post-build Pagefind step |
| Docusaurus | Algolia (requires qualification) | Medium |
Wiki Link Resolution Edge Cases
Most Dangerous Failure Modes
The most insidious wiki link issues are those that fail silently — no build error, no warning, just a broken link in production. Three patterns recur across SSGs:
Case sensitivity mismatch. Quartz resolves [[Note Two]] and [[Note two]] to different URLs. If the file is Note two.md, the capitalised variant produces a silent 404. Obsidian is case-insensitive; Quartz and most remark-based resolvers are not. This is an open bug in Quartz with no fix.
Ambiguous page names across subdirectories. When entities/Report.md and analysis/Report.md both exist, [[Report]] resolves non-deterministically (build-order dependent) in Quartz’s shortest mode, MkDocs roamlinks, Hugo, and Astro’s remark-wiki-link. Only MkDocs ezlinks with warn_ambiguities: true emits a warning.
Heading anchor divergence. The heading ## Conclusion & Future Work generates #conclusion--future-work (double hyphen) in remark-based parsers (Quartz, Astro) but #conclusion-future-work (single hyphen) in MkDocs and Hugo’s Goldmark. Wiki links with heading anchors copied between systems silently break.
Robustness Ranking
| SSG | Wiki Link Robustness | Broken Link Detection | Key Risk |
|---|---|---|---|
| Quartz | 7/10 — best Obsidian compatibility | None (silent 404s) | Case sensitivity bug |
| Eleventy + interlinker | 8/10 — best broken link detection | Console/JSON warnings | No block refs or transclusion |
| MkDocs + ezlinks | 7/10 — ambiguity warnings | CSS class only | Maintenance mode ecosystem |
| VitePress + remark-wiki-link | 6/10 — full feature set | CSS class only | Case-sensitive permalink matching |
| Starlight + starlight-obsidian | 6/10 — good plugin coverage | Validator plugin available | Small plugin (134 stars) |
| Hugo (custom) | 5/10 — maximum effort | Custom template possible | URL slug character stripping |
Mitigation Strategies
Regardless of SSG choice, three practices prevent the majority of wiki link failures:
- Use explicit subdirectory paths:
[[entities/Page Name]]instead of[[Page Name]]. Eliminates ambiguity entirely. - Enforce consistent casing: Run a linting script pre-build to catch case mismatches between link text and filenames.
- Add a CI broken link checker: None of the SSGs provide reliable comprehensive detection. Add
linkcheckeror a custom script as a CI step.
Auto-Deployment Pipelines
Summary Matrix
| Option | Free Build Limit | Deploy Speed | Bandwidth | Setup Time | Recommended |
|---|---|---|---|---|---|
| Cloudflare Pages (direct git) | 500 builds/mo | 30s–2 min | Unlimited | ~5 min | Yes |
| Netlify (direct git) | 300 min/mo | 1–3 min | 100 GB/mo | ~5 min | Viable |
| Vercel (direct git) | 6,000 min/mo | 30s–2 min | 100 GB/mo | ~5 min | ToS concern |
| GH Actions → Cloudflare Pages | 2,000 GHA min + 500 builds | 1–3 min | Unlimited | ~20 min | If build step complex |
| GH Actions → Netlify | 2,000 GHA min + 300 Netlify min | 1–3 min | 100 GB/mo | ~20 min | Unnecessary overhead |
| GH Actions → Railway | 2,000 GHA min + $5/mo | 1–3 min | Usage-based | ~30 min | Not recommended |
Recommendation: Cloudflare Pages Direct Git Integration
Cloudflare Pages is the clear winner for this use case (pages.cloudflare.com):
- 500 builds/month on the free tier — each push counts as one build regardless of duration. Pushing once daily uses 30 of 500.
- Unlimited bandwidth and static requests — no surprise suspensions, no metering (Cloudflare Pages pricing).
- ~30 second to 2 minute deploy time across 300+ global edge locations.
- Free SSL and custom domain support (up to 100 custom domains per project) (Cloudflare Pages limits).
- 5-minute setup: Connect GitHub repo → select branch → set build command → deploy. No YAML configuration required.
- 20,000 file limit on the free plan — a 200-page site is well within bounds.
Netlify is a strong second choice with an equally simple setup, but its free plan suspends the site for the rest of the month if limits are exceeded, and bandwidth is capped at 100 GB.
Vercel offers the most generous build minutes (6,000/month) but its Hobby plan is ToS-restricted to personal/non-commercial use, which matters for a business knowledge base.
Railway is not recommended — it has no permanent free tier ($5/month minimum after trial) and is designed for app backends, not static hosting (Railway pricing docs).
GitHub Actions pipelines (options 1–3) add setup overhead without meaningful benefit when the hosting provider’s built-in git integration handles the same workflow in fewer steps.
Access Control
Summary Matrix
| Option | Cost | Setup Complexity | Session Persistence | Security Level | Recommended |
|---|---|---|---|---|---|
| Cloudflare Access (email OTP) | Free (up to 50 users) | Medium (~15 min) | Cookie, configurable up to 1 month | Strong (identity-verified) | Yes |
| Netlify password protection | $19/mo (Pro plan) | Low (~2 min) | Browser session | Moderate (shared secret) | Only if already on Pro |
| HTTP basic auth (any host) | Free | Low (~5 min) | Browser session (native dialog) | Low | Not for non-technical users |
| Vercel password protection | $150/mo add-on | Low | Session-based | Moderate | Cost prohibitive |
| Private URL (no auth) | Free | None | N/A | None | Not for business content |
Recommendation: Cloudflare Access with Email OTP
Cloudflare Access is the only option that combines strong security, good user experience, and zero cost for this use case (Cloudflare Access docs):
- Free for up to 50 authenticated users on Cloudflare’s Zero Trust free plan (Cloudflare Zero Trust pricing).
- User experience: Mat visits the site → enters their email → receives a 6-digit PIN → enters PIN → gets access. The session cookie can be configured to last up to 1 month, so they won’t need to re-authenticate on every visit (Cloudflare One-Time PIN docs).
- Setup: In Cloudflare One dashboard, add an Access application for the Pages domain → create a policy allowing Mat’s email address → enable One-Time PIN as an identity provider. Takes ~15 minutes.
- Security: Identity-verified (email ownership confirmed via OTP), not a shared secret that could be forwarded or guessed. Appropriate for business-sensitive but not regulated content.
- Native integration: Works seamlessly with Cloudflare Pages since both are in the Cloudflare ecosystem — no proxy configuration or DNS changes needed.
Netlify’s site-wide password protection is simpler (shared password, no email step) but requires the $19/month Pro plan — it is not available on the free tier. The free tier only offers HTTP basic auth via _headers files, which presents an ugly native browser dialog.
Vercel’s password protection costs $150/month for production URLs, which is not viable for a single-user knowledge base.
A private URL (security through obscurity) is not a real access control mechanism and should not be used for business-sensitive content.
Recommended Stack
Primary Recommendation: Quartz + Cloudflare Pages + Cloudflare Access
| Layer | Choice | Rationale |
|---|---|---|
| SSG | Quartz v4 | Only SSG with native [[wiki link]] support matching all three Obsidian resolution modes. Zero-config graph view, backlinks, search, popover previews. 15–30 minute setup. |
| Search | FlexSearch (built into Quartz) | Sub-10ms results for sites up to 500K words. Cmd+K modal with highlighted excerpts. No setup required. |
| Hosting | Cloudflare Pages (direct git) | 500 builds/month, unlimited bandwidth, free SSL, custom domains. 5-minute setup. Auto-deploy on push. |
| Access control | Cloudflare Access (email OTP) | Free for up to 50 users. Mat authenticates with their email once per configurable session period (up to 1 month). Native Cloudflare integration. |
| Total cost | $0/month | All components on free tiers. |
Setup workflow:
- Fork Quartz → clone → copy Obsidian vault content into
content/directory - Set
markdownLinkResolutioninquartz.config.tsto match your Obsidian “New link format” setting - Disable graph view and Mermaid if page speed matters (
Plugin.ObsidianFlavoredMarkdown({ mermaid: false })+ comment outComponent.Graph()) - Push to GitHub → connect repo to Cloudflare Pages → site deploys
- In Cloudflare One dashboard, create an Access application → add Mat’s email to an Allow policy → enable One-Time PIN
Known trade-offs to accept:
- Single-maintainer project (bus factor 1) — mitigated by the site being static HTML that continues working even if Quartz development stops
- Case-sensitive link resolution — mitigate by enforcing consistent casing in the vault
- No build-time broken link detection — add a CI step with
linkcheckerif this matters - FlexSearch lacks true Levenshtein fuzzy matching — stemming and prefix matching are adequate for a knowledge base where the user knows the domain vocabulary
Runner-Up: Starlight + Pagefind + Cloudflare Pages + Cloudflare Access
| Layer | Choice | Rationale |
|---|---|---|
| SSG | Starlight (Astro) + starlight-obsidian plugin | Venture-backed Astro org, TypeScript frontmatter validation, starlight-links-validator for broken link detection. Slightly more future-proof than Quartz. |
| Search | Pagefind (built into Starlight) | Chunked loading (~100 KB), better ranking than FlexSearch, full drop-in UI. Zero config in Starlight. |
| Hosting | Cloudflare Pages | Same as above. |
| Access control | Cloudflare Access | Same as above. |
| Total cost | $0/month |
Choose this stack if long-term maintainability and broken link detection outweigh the faster initial setup of Quartz. The starlight-obsidian plugin is a smaller project (134 stars) than Quartz itself, but Starlight’s ecosystem (used by Cloudflare, Google, Microsoft) provides stronger institutional backing.
What to Avoid
- MkDocs Material: Maintenance mode since November 2025. Do not start new projects on a platform with an uncertain future.
- Docusaurus: No viable wiki link plugin. Requires the most effort to adapt Obsidian content.
- Hugo for this use case: Wiki link support requires writing and maintaining ~100 lines of custom Go templates. The maintainer has explicitly rejected native wiki link support.
- Railway for hosting: Costs $5/month for what Cloudflare Pages does for free.
- Vercel for hosting: ToS restricts Hobby tier to non-commercial use.
- Stork for search: Abandoned project.
- Lunr.js for search: Unmaintained since 2019.