Browse documentation

Getting started

Introduction

What ForgeCMS is, what it already does, and what it does not do yet.

ForgeCMS is a code-first, TypeScript-native CMS foundation with first-class Angular, Analog.js and Cloudflare support.

You describe your content in TypeScript:

import { defineCollection, defineField } from '@forge-cms/core';

export const posts = defineCollection({
  slug: 'posts',
  drafts: true,
  fields: {
    title: defineField.text({ required: true }),
    slug: defineField.slug({ autoGenerate: true, sourceField: 'title' }),
    body: defineField.richtext(),
    cover: defineField.upload({ collection: 'media' }),
    author: defineField.relation({ collection: 'users' })
  }
});

…and that one definition drives the database schema, runtime validation, the REST API, the admin UI form, and the types you get back in your Angular app. There is no schema file to keep in sync and no code generation step.

Why it exists

Every serious headless CMS in this space assumes React. Payload, Strapi and Sanity all ship React admin panels and React-shaped client libraries; using them from Angular means running someone else's framework beside yours, or hand-writing a client for a REST API you did not design.

ForgeCMS starts from the other end: Angular signals, Analog.js server routes, an admin panel that is Angular components you can import, and a Local API you call directly from server code — no HTTP hop between your Analog route and your content.

What is real today

  • Schema DSL and validation — 15 field kinds including group, array and blocks (the page-builder primitive), validated at runtime on every write.
  • A typed Local API — find, findOne, findByID, create, update, delete, count on the runtime object, running the full pipeline (access control, hooks, drafts, relation population, validation) and inferring documents from your collection definitions.
  • A REST API — CRUD with filtering (including nested and/or), multi-field sorting, pagination, relation population and draft visibility, in a stable envelope.
  • Access control as functions — a rule can return true/false or a query that narrows which documents the operation may touch (row-level rules like "authors edit only their own posts").
  • A full hook pipeline — nine collection stages plus per-field hooks.
  • Real auth — users stored in your database with PBKDF2 hashing, cookie sessions with CSRF protection, scoped API keys, and admin/editor/viewer roles.
  • Content lifecycle — drafts, document versions with restore, live preview, globals, localization and relation integrity rules on delete.
  • Uploads — multipart/form-data creates through a StorageAdapter, with a file-serving handler.
  • Adapters — in-memory, LibSQL/Turso and Cloudflare D1 for the database; in-memory and R2 for storage; all held to a shared contract test suite.
  • An Angular client and admin UI — CmsApiService plus signal-based resources, a cookie session and route guard, and an admin you mount under your own routes (content, users, sign-in).

What is experimental

Be honest with yourself about this list before adopting it for something that matters:

  • Stable 1.0. The twelve-package fixed family is published at 1.0.0. The accepted 1.0.0-rc.2 remains part of release history. Install stable packages at matching versions; the experimental Agent Kit and Cloudflare Analytics remain outside the 1.x compatibility promise. See Support and compatibility.
  • Schema upgrades are explicit. Schema sync applies safe additive changes and refuses drift that needs a data migration. Reviewed migrations apply those changes from your deploy script, exactly once. There are no down migrations. Upgrades from older releases and backup/restore are rehearsed in CI on libSQL and local D1/R2, and the Cloudflare profile's backup and isolated restore were rehearsed on real isolated Cloudflare staging. See Schema upgrades.
  • Relation population is one level deep (depth: 1), and composite JSON values cannot be queried inside.
  • SSR uses an explicit server origin. Public pages render and hydrate with provideForgeCmsServer and a credentials: 'omit' client (see SSR); server routes can still call the Local API directly.
  • Durable storage is R2 or S3. @forge-cms/s3 covers S3-compatible services (Garage is CI-certified; AWS S3, B2 and Wasabi are configurable, not certified). In-memory storage is development-only.
  • No email adapter, plugin system, or CLI.

How the pieces fit

Your Angular app  ──►  @forge-cms/angular  ──►  HTTP /api/v1/*  ──┐
                                                                  ├─►  @forge-cms/runtime  ──►  adapters (db / auth / storage)
Your server route ──►  runtime.find(...)  (Local API, no HTTP)  ──┘

@forge-cms/core defines the schema, @forge-cms/runtime executes operations, and the adapter packages talk to the outside world. Read Core concepts for the full picture.

Where to go next

The repository also keeps a maintainer-facing record: docs/STATE.md (what is implemented, package by package), docs/ARCHITECTURE.md, and docs/specs/ (one spec per feature, with the reasoning behind it).