# How the CMS works

Understand what saving, publishing, previewing and scheduling actually change.

GroCMS 0.1.0 · Start here · Everyone using the CMS · Reviewed 15 September 2026

## The editor and website can show different saved versions

GroCMS keeps the version you are working on separate from the version visitors can see. Saving a title, body or layout creates a new saved revision. Publishing chooses a particular saved revision for the website. If you publish an article and then change its introduction, visitors continue to receive the published introduction until someone with permission publishes the later revision. A successful save is therefore evidence that your work is stored, not that it is public.

This distinction also applies to design. Templates, shared sections, menus, brand identity and site settings have working and published versions. You can prepare a new header without changing the current site. Publishing the header makes that design available to the pages that use it. An unpublished edit to a category name, an author profile or a media replacement must not slip into an otherwise published page.

Sources: Resource and revision contracts (repository: `apps/cms/src/cms/contracts.ts`); Save, publish, restore, preview and schedule services (repository: `apps/cms/src/cms/services/content.ts`).

## Content and design share one resource model

A resource is an item with a continuing identity: a Post, Page, Event, Vehicle, taxonomy term, template, section, menu, brand, settings record or author profile. Its revisions are the saved versions of that item. A revision includes the title and content plus relevant fields, relationships, visibility, layout and search-engine information. References use stable identifiers, so changing a label does not turn the relationship into a different item.

Each resource remembers its working revision and, when published, its published revision. History is preserved rather than rewritten in place. Restoring an older revision creates another working revision containing that older snapshot; it does not erase the intervening history or automatically replace the public version. This lets an editor inspect the restored result before making a publication decision. Retention can eventually remove eligible old history through a separate audited maintenance process.

Sources: Resource and revision contracts (repository: `apps/cms/src/cms/contracts.ts`); Registered content types (repository: `apps/cms/src/cms/definitions/index.ts`); Save, publish, restore, preview and schedule services (repository: `apps/cms/src/cms/services/content.ts`).

## Publication changes related records together

Publishing is more than changing a status label. The server checks your current authority, the exact saved revision, required fields, referenced items and route availability. It then changes the public revision, route records, public search entry, publication record and queued publication effect within one database transaction. Either those changes commit together or they are rolled back. A route collision or missing required dependency should leave the previous website intact.

A short site-level database lock coordinates changes that could otherwise make incompatible decisions at the same time. For example, one person must not withdraw a section while another person publishes a new page that requires it. This coordination is separate from the version check that catches two people saving from the same older revision. On a conflict, compare your local work with the newly saved version; repeatedly forcing the old request is not a reconciliation strategy.

Sources: Save, publish, restore, preview and schedule services (repository: `apps/cms/src/cms/services/content.ts`); Transactional queue configuration (repository: `apps/cms/src/cms/jobs/queue.ts`); [ORM Transaction Adapters](https://pgboss.io/api/adapters).

## A page uses a consistent public view

The public loader reads the page, applicable template and required shared resources from one read-only database snapshot. A publication that finishes during the request cannot make the first half of that request use one public state and the second half use another. PostgreSQL calls this transaction setting repeatable read. The CMS separately enforces which records are eligible to be public; the database isolation setting alone does not decide content permissions.

Archives and search use current public revisions, not whichever revision was edited most recently. Media files live outside the public application assets. The media endpoint checks whether the requested version is referenced by eligible public content or is available to the authenticated viewer. Uploading or replacing an image does not, by itself, publish it. Old revisions continue to point to the old immutable media version until their content is deliberately changed.

Sources: Public snapshot and query loader (repository: `apps/cms/src/cms/services/public.ts`); Private media access and versioning (repository: `apps/cms/src/cms/services/media.ts`); [PostgreSQL 18: Transaction Isolation](https://www.postgresql.org/docs/18/transaction-iso.html).

## Preview and scheduling select exact revisions

A preview is a temporary selection of saved revisions layered over the published site. Only the chosen overrides are included; unrelated drafts remain excluded. Preview links expire after thirty minutes and require the account that created them. Treat them as your authenticated review session, not as anonymous links to distribute outside the workspace. Save the relevant work first, then create a new preview when the selected revision or expiry no longer matches your intention.

A schedule records the intended revision, due time and expected publication version. Later draft edits do not silently change the scheduled revision. The separate worker rechecks durable schedule state and current publishing authority before execution. Cancellation, revoked access, a conflicting dependency or a newer manual publication can prevent the old intention from publishing. Temporary infrastructure failures can be retried; a blocked publishing decision needs a person to resolve its stated cause.

Sources: Save, publish, restore, preview and schedule services (repository: `apps/cms/src/cms/services/content.ts`); Worker execution and retry handling (repository: `apps/cms/src/worker/handlers.ts`).

## Use the right controls for your responsibility

Your role determines what you can create, edit, review and publish. Administrators manage the workspace; editors manage editorial resources; designers manage website design; authors and contributors have narrower ownership-based paths. The server reloads current account authority when processing changes, so an open browser tab does not preserve permissions after they have been revoked. API credentials also have scopes that can further restrict the account behind them.

Editors normally work entirely in the administration screens. Developers register new content types and component contracts in code. Operators maintain the database, media volume, worker, backups and deployment. Keeping these responsibilities clear makes problems easier to diagnose: an unpublished revision needs an editorial decision, a missing worker needs an operational fix, and a new field kind needs a compatible implementation and tests.

Sources: Role and capability policy (repository: `apps/cms/src/cms/policy/index.ts`); Save, publish, restore, preview and schedule services (repository: `apps/cms/src/cms/services/content.ts`).

## References

- Resource and revision contracts — repository path: `apps/cms/src/cms/contracts.ts`

- Registered content types — repository path: `apps/cms/src/cms/definitions/index.ts`

- Save, publish, restore, preview and schedule services — repository path: `apps/cms/src/cms/services/content.ts`

- Public snapshot and query loader — repository path: `apps/cms/src/cms/services/public.ts`

- Private media access and versioning — repository path: `apps/cms/src/cms/services/media.ts`

- Role and capability policy — repository path: `apps/cms/src/cms/policy/index.ts`

- Transactional queue configuration — repository path: `apps/cms/src/cms/jobs/queue.ts`

- Worker execution and retry handling — repository path: `apps/cms/src/worker/handlers.ts`

- [PostgreSQL 18: Transaction Isolation](https://www.postgresql.org/docs/18/transaction-iso.html). Repeatable-read background; CMS access policy is implemented in the cited source.

- [ORM Transaction Adapters](https://pgboss.io/api/adapters). Explains transaction-bound enqueue; the application pins 12.30.0, while this rolling documentation currently identifies 12.31.0.

## Related guides

- [Technology stack](https://grocms.com/docs/technology-stack)

- [Content types and extensions](https://grocms.com/docs/content-types)

- [Troubleshooting](https://grocms.com/docs/troubleshooting)
