{
  "slug": "framework-agnostic",
  "title": "Framework-Agnostic Architecture",
  "description": "Your content as flat JSON files. Render it with any language, any framework, any runtime.",
  "category": "consumers",
  "order": 1,
  "locale": "en",
  "translationGroup": "3103a635-8d32-4f30-adc7-45e82abff87a",
  "helpCardId": null,
  "content": "## The big idea\n\n**@webhouse/cms stores content as flat JSON files.** Not in a database. Not behind an API. Just files in a directory:\n\n```\ncontent/\n  posts/\n    hello-world.json\n    hello-world-da.json\n    my-second-post.json\n  pages/\n    about.json\n    contact.json\n  globals/\n    site.json\n```\n\nEvery language that can read a file can consume this content. PHP, Python, Ruby, Go, C#, Rust, Elixir, Haskell, Bash — they all speak JSON.\n\n## Why this matters\n\nMost CMS platforms lock you in. Contentful requires their SDK. Sanity wants their GROQ queries. WordPress needs PHP + MySQL. Strapi runs its own Node server. If you want to switch stacks, you export, migrate, and pray.\n\nWith @webhouse/cms, **your content is files in your git repository.** No lock-in. No migration. No vendor dependency. If you want to replace @webhouse/cms tomorrow with a different admin UI, your content is already in a portable format.\n\n## What's TypeScript-specific\n\nOnly the **admin layer**:\n\n- `cms.config.ts` — the schema definition (TypeScript)\n- Admin UI (Next.js)\n- AI agents (TypeScript)\n- Optional `@webhouse/cms` Next.js helpers\n\nThat's it. Everything below the admin layer is framework-agnostic.\n\n## What's framework-agnostic\n\n| Component | Format | Consumable by |\n|-----------|--------|---------------|\n| Content | JSON files | Anything that reads files |\n| Media | Image files in `public/uploads/` | Any web server |\n| Schema | Exportable as JSON Schema ([schema export →](/docs/schema-export)) | Any JSON Schema library |\n| SEO | `sitemap.xml`, `robots.txt`, `llms.txt` | Standards-compliant crawlers |\n| MCP | Public read-only MCP server | Any AI agent |\n\n## The content format\n\nEvery document follows the same structure:\n\n```json\n{\n  \"slug\": \"hello-world\",\n  \"status\": \"published\",\n  \"locale\": \"en\",\n  \"translationGroup\": \"uuid-shared-with-translations\",\n  \"data\": {\n    \"title\": \"Hello, World!\",\n    \"content\": \"## Welcome\\n\\nThis is my first post.\",\n    \"date\": \"2026-04-08\",\n    \"tags\": [\"intro\", \"hello\"]\n  },\n  \"id\": \"unique-id\",\n  \"_fieldMeta\": {}\n}\n```\n\nTo filter published content, skip anything where `status !== \"published\"`. To read only one language, filter by `locale`.\n\n## Reading content from any language\n\nThe pattern is always the same:\n\n1. List files in `content/<collection>/`\n2. Parse each JSON\n3. Filter where `status === \"published\"`\n4. Optionally filter by `locale`\n5. Sort / render as needed\n\nSee the framework-specific guides:\n\n- [Consume from Laravel (PHP)](/docs/consume-laravel)\n- [Consume from Django (Python)](/docs/consume-django)\n- [Consume from Rails (Ruby)](/docs/consume-rails)\n- [Consume from Go](/docs/consume-go)\n- [Consume from C# / .NET](/docs/consume-dotnet)\n\n## The admin stays the same\n\nRegardless of which framework you use to render the site, the CMS admin UI is the same Next.js application. Editors log in, edit content, hit publish — and the JSON files update in your git repository.\n\n## What about building?\n\n**F126** (planned) will let CMS admin invoke ANY build command — `php artisan build`, `hugo --minify`, `bundle exec jekyll build`, `python manage.py collectstatic` — not just our native TypeScript pipeline. Today you can still trigger builds via git hooks, CI/CD, or your own scripts.\n\n## Schema export\n\nNon-TypeScript runtimes can't execute `cms.config.ts`, so the CMS exports a [JSON Schema document](/docs/schema-export) (`webhouse-schema.json`) that describes the content model in a language-agnostic way. Reader libraries use this file to introspect collections, generate types, and validate documents.\n\nGenerate it from the **CMS admin UI** (Site Settings → Schema export → Save to project root) or from the **CLI**:\n\n```bash\nnpx cms export-schema --out webhouse-schema.json\n```\n\n[Read the full schema export guide →](/docs/schema-export)\n\n## Trade-offs\n\n**File-based content is not for everyone.** Consider:\n\n- **Scale** — thousands of documents work fine. Millions do not. Use a database adapter if you need scale.\n- **Concurrent writes** — filesystem adapter is single-writer. If you need real-time multi-editor, use the Supabase adapter.\n- **Search** — no built-in full-text search. Use a separate search index (Algolia, Meilisearch, Typesense).\n\nFor 95% of content-driven sites, file-based content is faster, simpler, and safer than any database.\n\n## Next steps\n\n- Read [Introduction](/docs/introduction) for the overall architecture\n- Pick your framework from the consumer guides above\n- Look at the [examples](https://github.com/webhousecode/cms/tree/main/examples) for working code",
  "excerpt": "The big idea\n\n@webhouse/cms stores content as flat JSON files. Not in a database. Not behind an API. Just files in a directory:\n\n\ncontent/\n  posts/\n    hello-world.json\n    hello-world-da.json\n    my-second-post.json\n  pages/\n    about.json\n    contact.json\n  globals/\n    site.json\n\n\nEvery language ",
  "seo": {
    "metaTitle": "Framework-Agnostic Architecture — webhouse.app Docs",
    "metaDescription": "Your content as flat JSON files. Render it with any language, any framework, any runtime.",
    "keywords": [
      "webhouse",
      "cms",
      "framework-agnostic",
      "json",
      "documentation"
    ]
  },
  "createdAt": "2026-04-08T12:00:00.000Z",
  "updatedAt": "2026-04-08T12:00:00.000Z"
}