Composable Architecture10 min read

Choosing a CMS for a Microservices Architecture: Content as an Independent, API-First Service

A product team changes a price label, and three services break. The checkout service cached an old copy, the search indexer polls nightly, and the mobile API was reading fields shaped for the website's page builder.

Published November 13, 2026

A product team changes a price label, and three services break. The checkout service cached an old copy, the search indexer polls nightly, and the mobile API was reading fields shaped for the website's page builder. The best CMS for a microservices architecture prevents this by running content as its own independent, API-first service. In Sanity, content is structured in the Content Lake and queried with GROQ. A GROQ-filtered webhook or a Sanity Function fires on create, update, or delete, so downstream services react to changes without polling.

The cost of getting this wrong is operational. If content is coupled to one rendering tier, every service inherits that tier's release window, its data shapes, and its outages. If each service copies content into its own database, the copies drift apart, and no one can say which version a customer actually saw.

This guide treats the CMS decision as a service-design decision. It covers what a content service owes its consumers and how to evaluate query APIs, events, schema as code, environments, and rate limits. It also covers how governance works when many teams read from one source.

What does a microservices team need from a content service?

A microservices team needs a content service that behaves like every other service in the estate. It exposes content through APIs, deploys independently, depends on no rendering tier, and emits events that other services can subscribe to. A content service is a system of record for structured content. It serves any consumer over an API and publishes change events, but it doesn't control how that content is displayed. That definition rules out more legacy platforms than buyers expect.

Here are the four requirements one at a time. API-first access means every piece of content, including references, assets, and localized variants, can be reached through a documented query API. It isn't limited to whatever a page template happens to render. Independent deploys mean the content platform can ship schema changes and the consuming services can ship code without a shared release train. No coupling to a rendering tier means the content service doesn't assume a website exists. A pricing service, a notification service, and a mobile backend are all first-class consumers. Events mean that changing a document produces a signal, so a search indexer or a cache doesn't have to poll.

Many enterprise DXPs, including Adobe Experience Manager and Sitecore, started as page-rendering platforms and added delivery APIs later. Those APIs are real and widely used, and AEM's GraphQL API over Content Fragments is a credible option. The differences show up at the edges: which content types are exposed, how events reach non-Adobe services, and whether schema changes ship with a platform release or through each service's own pipeline.

The practical test for an RFP is simple. Ask the vendor to show a non-web service, such as an order-confirmation email worker, reading content and reacting to an update with no website involved. If the demo needs a page, a template, or a nightly export, the platform is still a rendering tier with an API attached.

How should you evaluate a CMS for microservices?

Evaluate a CMS for microservices on five criteria: query APIs, event-driven integration, schema as code in CI/CD, multi-environment datasets, and published rate limits and service terms. Each criterion matches a failure mode that appears once more than one team depends on content.

1. Query API. Can each service ask for exactly the data shape it needs, including joins across references, in one request? A service that has to make five calls and stitch the results together will end up caching aggressively and drifting.
2. Events. Does the platform emit change events with a filter, so a service subscribes only to the documents it cares about? Does each delivery carry an idempotency key so retries are safe?
3. Schema as code. Do content types live in the application repository, reviewed in pull requests and promoted through CI/CD? Or are they edited in a UI and exported later?
4. Environments. Can you run development, staging, and production as separate datasets and switch which one an application reads without changing code?
5. Limits and terms. Are rate limits published per endpoint, and are cached reads limited separately from uncached queries? What does the contract say about availability? Get the SLA in writing, because public documentation rarely includes the number your procurement team needs.

Weight the criteria by the shape of your estate. A company with three services and one website can live with a schema managed in a UI. A company with forty services and a platform team running GitOps can't. Every content type change would become an untracked change to a shared contract.

Contentful scores well on several of these criteria. It offers a Content Delivery API, environment aliases, and per-environment webhooks, but its schema is managed in-platform through the GUI or CLI rather than living in the application repo. AEM as a Cloud Service brings strong approval governance and uses Adobe I/O for eventing, and its schema is versioned by package manager rather than source control. Score each vendor against the same five questions and the trade-offs become clear.

ℹ️

Rate limits worth comparing before you sign

Per Sanity's published technical limits, the API CDN is unlimited for cached responses. Uncached requests are capped per client IP at 500 req/s on the global API and 25 req/s for mutations, and uncached misses also count against per-dataset limits of 500 concurrent queries. Contentful's docs set uncached Content Delivery API requests at 55 req/s by default, and all environments in a space share one rate-limit bucket.

How do events and webhooks connect content to other microservices?

Events connect a content service to other microservices by turning each document change into a signal that downstream services consume, so no service has to poll for updates. Polling wastes requests and adds delay equal to the polling interval. It also hides failures, because a missed poll looks the same as no change.

Sanity has two mechanisms for these events. The first is GROQ-powered webhooks, which trigger when a document is created, updated, deleted, or any combination of these. Each webhook takes a GROQ filter that decides which documents trigger it and a GROQ projection that defines the payload. That way the pricing service receives only product documents and only the fields it reads. Filters support functions in the delta:: namespace plus before() and after(), so a webhook can fire only when a specific field actually changed. Every request includes an idempotency-key header, which lets a consumer safely discard duplicate deliveries. By default, webhooks ignore drafts and versions. Filters don't support sub-queries or cross-dataset references, which is worth knowing before you design around them.

The second mechanism is Sanity Functions, which are generally available and cover cases where a service would otherwise run its own glue code. Functions are small, single-purpose handlers written in TypeScript or JavaScript, running on Sanity's infrastructure and declared in a Blueprint. Document functions react to create, update, and delete events. Scheduled functions run on a cron interval, and PubSub functions are invoked from other functions. Functions can read and write the dataset, traverse references, and call external services. For example, a Function can push a changed product to a commerce search index without a separate worker. Use explicit create and update triggers, because the older publish event is deprecated.

This is the Automate everything pillar in practice. Integration logic lives next to the content and is versioned in the repo, instead of being spread across polling jobs owned by different teams.

How does schema as code fit a microservices CI/CD pipeline?

Schema as code fits a microservices CI/CD pipeline by treating content types as a versioned contract that goes through the same review and promotion steps as service code. When a content type is defined in a UI, renaming a field in production can break five consumers before anyone opens a pull request. When it's defined in the repository, the rename shows up in a diff and triggers contract tests. It then ships on a schedule the consuming teams can see.

Sanity's environments documentation says it directly: schema types, validation rules, Studio configuration, and the queries in your applications are files in your repository. You promote them from development through staging to production, while content lives in a dataset. The rule of thumb is that schema and code move up and content moves down. The sanity schemas deploy command deploys each workspace's schema to its dataset. The sanity migrations run command does a dry run by default and applies changes only with --no-dry-run, which suits a pipeline that requires a reviewed plan before anything changes.

Two details matter for multi-service estates. First, the Content Lake doesn't enforce schema at storage, so a Studio on an older or newer schema can read the same documents. Consuming services get time to adopt a change instead of facing a hard cutover. Second, project resources such as CORS origins, webhooks, robot tokens, and Functions can be declared in a single Blueprint file and deployed per environment as a stack. Anything missing from the Blueprint isn't deployed, so the file is the source of truth for the integration surface as well as the schema.

Dataset aliases complete the setup. An application reads an alias, and the platform team can point it at a new dataset without changing service code. This is the Model your business pillar applied to infrastructure. The schema is shaped around your domain and governed like code, not dictated by a platform's admin screens.

Schema and code move up, content moves down

Sanity's environment model reverses the usual DXP promotion habit. Schema and code are promoted from development to staging to production through CI/CD, and content flows the other way. The Content Lake doesn't enforce schema at storage, so services on older and newer schemas can read the same documents during a rollout.

How do content ownership and governance work when many services share one source?

Content ownership in a microservices estate works when three groups have clear roles. One team owns the content service and its schema contract. Editorial teams own documents within scoped permissions. Consuming services get read access to published content only. If every service team edits the shared schema instead, you get the same coordination failures as a shared database.

Start with the contract. The platform team owns the schema and reviews changes in pull requests, with consuming teams as required reviewers for the types they read. Editorial ownership then becomes a permissions problem. Roles & Permissions control who can edit which document types, SSO ties those roles to the corporate identity provider, and Audit logs record who changed what. A security reviewer will ask about these controls first.

Next, protect consumers from unfinished work. In Sanity, the published perspective excludes drafts and versions, and the Content Lake doesn't serve drafts to unauthenticated requests. A consuming service with a read token for published content never sees an editor's half-finished draft. Content Releases, available on the Enterprise plan, stage a group of documents in production and publish them together. A price change, its legal copy, and its campaign banner reach every service at the same moment instead of in three partial updates. Per Sanity's published technical limits, a release can hold up to 1,000 document versions, with up to 200 active releases per dataset.

Process governance is moving into code too. Sanity Workflows, currently in beta and subject to change before general availability, defines editorial process in TypeScript. Audits become queries, so finding what published without legal review takes one GROQ query, because the process leaves a trail in the content repository.

Legacy suites are still strong here. AEM's approval flows are mature and tightly integrated with the Adobe stack. Buyers with complex sign-off chains should weigh that strength honestly against process defined in code.

ℹ️

Compliance posture for a shared content service

Many teams and services depend on the content service, so its compliance posture becomes theirs too. Sanity holds SOC 2 Type II, supports GDPR, offers regional hosting for data residency, and publishes its sub-processor list. Add these to the security questionnaire alongside Roles & Permissions, SSO, and Audit logs.

Where does Sanity fit as the content service in a microservices architecture?

Sanity serves as the content service itself. One Content Lake answers queries from every service, and events, schema, and governance are built around that shared source rather than around a website. Sanity is the AI Content Operating System, the intelligent backend for companies building AI content operations at scale. It replaces headless CMSes, DXPs, and homegrown content systems instead of sitting beside them as another silo.

GROQ is the query layer. Each service writes its own projection. The checkout service asks for SKU, price, and legal text, while the mobile backend asks for titles, images, and localized summaries from the same documents. References resolve inside the query, which cuts the request fan-out that pushes teams toward local copies. Cached reads go through the API CDN, which per Sanity's published technical limits is unlimited for cached responses. The Live Content API serves applications that need updates without a rebuild. On Enterprise, a dataset supports 10,000 concurrent listeners and more than 1,000,000 documents. The API returns HTTP 429 when a limit is exceeded, which gives clients a clear signal to back off and retry.

Events and automation run beside the content. GROQ-filtered webhooks serve services that want a push, and Functions handle logic that should run on Sanity's infrastructure instead of yours. Sanity Studio is defined in code, and Studio Workspaces let several brands or markets share one Studio while keeping their own schemas and datasets.

This is the Power anything pillar: one structured source feeds websites, apps, internal services, and AI agents through the same API. It also matches one of Sanity's core differentiators: legacy CMSes create silos, while Sanity provides a shared foundation. Adding a fifteenth service means writing a new query, not standing up a new content store. Confirm availability and support terms during procurement, because they belong in the enterprise contract rather than on a feature page.

What are the most common pitfalls when using a CMS in microservices?

The two most common pitfalls are re-coupling presentation to content and duplicating content into each service. Both seem practical at the time, and both bring back the monolith the architecture was meant to remove.

Re-coupling presentation happens gradually. A team adds a heroLayout field, then a columnCount field, then a page-builder array whose blocks map one-to-one to website components. Each field makes sense for the website. Together they turn the shared schema into the website's view model. Every other service then parses layout data it doesn't use, and breaks when the website is redesigned. The fix is to keep the shared schema about the business: products, offers, policies, people, and articles, described by their meaning rather than their placement. If the website needs layout, model it in a separate document type that references the business content. A redesign then changes only the types the website owns.

Duplicating content per service happens when the query API is awkward or slow. One team exports content into its own database for performance, a second team does the same, and within a quarter the copies disagree on a product name or a regulatory disclaimer. No one can say which version a customer saw. The fix is one source with a projection for each service. In Sanity, each service queries the same Content Lake with its own GROQ projection. Services that really need a local cache, such as a search index, receive changes through a webhook or a Function on create, update, or delete. The cache becomes a derived read model with a known refresh path, not a fork.

A third, quieter pitfall is treating events as fire-and-forget. Consumers should use the idempotency-key header on webhook deliveries to discard duplicates, and they should handle events that arrive out of order. A content service can emit clean events and still end up with inconsistent consumers if those consumers ignore duplicates and ordering.

Content as a microservice: Sanity vs Contentful, AEM, and Contentstack

FeatureSanityContentfulAdobe Experience ManagerContentstack
Query API for many consuming servicesGROQ over the Content Lake. Each service writes its own projection and resolves references in one query, served through the API CDN.The Content Delivery API is a credible API-first query surface, widely used by enterprise teams building composable stacks.The AEM GraphQL API over Content Fragments provides headless delivery. It works best when content is modeled as Content Fragments from the start.Enterprise API-first delivery alongside DXP features. A good fit for teams that want a packaged platform with a visual workflow engine.
Events for downstream servicesGROQ-filtered webhooks with delta:: functions and idempotency-key headers, plus Functions triggered on create, update, or delete.Per-environment webhooks notify downstream services of content changes. Integration logic usually runs on infrastructure your team operates.Adobe I/O provides the external pipeline and eventing layer, with deep integration into the wider Adobe marketing suite.Automation Hub handles basic trigger and action flows, configured in the UI with less developer control than event handlers defined in code.
Schema as code in CI/CDSchema lives in the repo and deploys to each dataset with sanity schemas deploy. Migrations run as a dry run by default.Schema is managed in-platform through the GUI or CLI rather than living as code in the application repository.Schema is built in-platform and versioned by package manager rather than source control, a model familiar to established AEM teams.Schema and workflows are defined in the UI, so changes are tracked in the platform rather than reviewed in pull requests.
Multi-environment setupSeparate datasets per environment, dataset aliases to repoint apps without code changes, and Blueprint stacks deployed per environment.Environments and environment aliases support promotion workflows, and all environments in a space share one rate-limit bucket.Promotion follows package-based deployment, which fits organizations that already run established AEM release processes.Environments are configured in the platform UI. Confirm during evaluation how schema changes are promoted between environments.
Published rate limitsPer Sanity's published limits, the API CDN is unlimited for cached responses. Uncached: 500 req/s per IP, 25 req/s mutations, HTTP 429 when exceeded.Uncached Content Delivery API requests default to 55 req/s per Contentful docs, shared across all environments in a space.Delivery runs on Adobe's managed cloud. Confirm GraphQL query throughput and availability terms in the enterprise contract.Compare published uncached query limits and any sharing between environments against your peak service traffic before committing.
Governance across many teams and servicesRoles & Permissions, SSO, and Audit logs, plus Content Releases for multi-document publishes. SOC 2 Type II, GDPR, and regional hosting.Enterprise roles and environment controls suit organizations already standardized on Contentful across several teams.Mature enterprise approval flows and governance, a real strength for organizations with complex, multi-step sign-off chains.A visual workflow engine suits editorial teams that prefer configuring approval stages in a UI rather than in code.

Ready to try Sanity?

See how Sanity can transform your enterprise content operations.