An open-source, multi-tenant headless CMS you self-host on Firebase.
日本語版 README はこちら / Japanese README
Sign up, create a space, define your content models in a GUI model builder, and start writing. Your website reads the content through a zero-dependency SDK (or plain REST) — no servers to run, nothing but Firebase (Firestore / Storage / Hosting / Auth).
This project grew out of deep respect for Newt,
the Japanese headless CMS that shuts down in October 2026. It deliberately
inherits Newt's excellent design — the Space > App > Model > Field hierarchy,
asset handling, and depth-based reference resolution — and aims to be
a place Newt users can migrate to as-is:
- newt-client-js-compatible SDK —
switching a site takes a few lines (the import and
createClient) - One-command migration from Newt — bundled scripts export every model, content item, and image from the Newt CDN API and import them into your Firebase project (docs/newt-migration.md)
- Content storage format is compatible with Newt's depth=0 representation
With gratitude to the Newt team for what they built.
- Self-service: sign up with email/password or Google → create a space
(globally unique
spaceUid) → create apps → define models → write content - Model builder: 11 field types (text / textarea / html / number / boolean / date / select / image / imageList / objectList / refList), title field and default sort configuration. Destructive changes (uid/type edits) are blocked once a model has content
- Multi-tenant: many users and spaces share one Firebase project, with owner / editor roles and email invitations
- Media library: space-wide shared assets, reusable from image fields
- Tokenless public delivery: websites read Firestore over REST directly,
keeping running costs minimal. Security rules are membership-based
(authorization on writes only — no billed
get()calls on the read hot path) - "Settings & Integration" screen in the admin: connection values, copy-paste SDK snippets, and REST endpoints for your frontend
- MCP server for AI agents: a stdio
MCP server
(
@bridgeuidev/cms-mcp) for Claude Code / Claude Desktop, plus a remote Cloud Functions endpoint you can add in claude.ai — log in with your CMS account over OAuth and write with your own membership. Writes are always gated by the membership rules; content writes (create/update/delete_content) need owner/editor, while model management (create/update/delete_model) is owner-only (docs/mcp-server.md)
Note: the admin UI is currently Japanese-only. i18n is on the roadmap (see docs/DESIGN.md §8 — the design document itself is maintained in Japanese as the project's source of truth).
├── packages/schema/ FieldDef vocabulary + validators + interpreters (+ a sample portfolio template)
├── packages/client/ newt-client-js compatible read SDK → npm: @bridgeuidev/cms-client
├── packages/mcp/ MCP stdio server for AI agents (read/write) → npm: @bridgeuidev/cms-mcp
├── admin/ Vue 3 + Vite + Tailwind admin UI (spaces, model builder, content entry)
├── scripts/ Firebase provisioning / Newt migration scripts
├── docs/ design doc, setup, migration, maintenance policy
├── firestore.rules membership-based (public content reads, owner/editor writes)
└── storage.rules protects spaces/{spaceId}/assets/** by membership
The architecture, data design, and roadmap live in docs/DESIGN.md (Japanese; Phases 1–2 — runtime schemas and multi-tenancy — are implemented).
Prerequisites: Node.js 18+, and the firebase CLI and gcloud CLI, both logged in.
git clone <this-repo> && cd <repo>
npm install
# Provision everything: project, APIs, Firestore, Storage, Auth, deploy
npm run setup:firebase -w scripts -- --project <your-project-id> --createWhen it finishes, the admin UI is live at https://<your-project-id>.web.app.
The first user to sign up creates a space and becomes its owner.
Manual steps and troubleshooting: docs/SETUP.md.
npm install @bridgeuidev/cms-clientimport { createClient } from '@bridgeuidev/cms-client'
const client = createClient({
projectId: '<firebase-project-id>',
spaceUid: '<your-space>',
appUid: '<your-app>'
})
const { items } = await client.getContents({ modelUid: 'article', query: { depth: 2 } })Copy the exact values from the admin's "App > Settings & Integration" screen. See docs/website-integration.md for the integration guide and packages/client/README.md for the full API reference.
npm run export:newt -w scripts -- --space <spaceUid> --app <appUid> --token <CDN API token>
npm run import:firebase -w scripts
npm run seed:space -w scripts -- --owner-email <you@example.com> \
--space-uid <spaceUid> --app-uid <appUid> --models-from-manifest
npm run migrate:assets -w scripts -- --space-uid <spaceUid>Model definitions (field types are auto-inferred), all content, and all images come across with content IDs preserved. Full walkthrough: docs/newt-migration.md.
firebase emulators:start # auth:9099 / firestore:8080 / storage:9199 / UI:4000
VITE_USE_EMULATORS=true npm run devOn macOS the emulators fail to start under the system Java 8 — install a
Homebrew OpenJDK and put it on your PATH
(PATH="/opt/homebrew/opt/openjdk/bin:$PATH").
Versioning, support scope, security reporting, and publication policy: docs/MAINTENANCE.md.