Contoprix
GraphQL CMS

Shape published content with GraphQL, without guessing the schema.

Contoprix generates a tenant-aware GraphQL delivery schema from structured content models, then lets server-side applications query published site, page, navigation, component, and relation fields.

Definition

What is a GraphQL CMS?

A GraphQL CMS exposes structured content through a typed graph so an application can select the published fields needed for a particular view.

The CMS still owns modeling, editorial workflow, localization, publication, permissions, and media. GraphQL is the delivery boundary between that governed content layer and an application. The frontend chooses fields, but it can only query types and relations present in the current schema.

This page focuses on that delivery contract. For the broader separation between content and presentation, start with the headless CMS architecture guide.

Contoprix also provides REST routes and framework SDK helpers. A team can use GraphQL for one complex server-rendered view and the standard SDK for routine page delivery without making one interface mandatory everywhere.

Delivery Flow

The content model becomes an application query contract

Stable website roots are combined with tenant-generated content types. Normal requests resolve only published data for the website associated with the credential.

01

Structured model

Enabled types, fields, components, and relations

02

Tenant schema

Stable roots plus generated model-specific fields

03

POST /graphql

Scoped, read-only published delivery

04

Application

Reviewed query, server cache, and rendered UI

Verified Schema Behavior

Stable roots for websites, generated fields for content models

The public contract has a dependable system layer while allowing each tenant’s structured model to define its own content graph.

Stable system roots

Every tenant schema includes site, navigation, page, and pageById fields for published website delivery.

Model-generated fields

Enabled content types and their fields become tenant-specific GraphQL types and query roots using deterministic naming rules.

Structured relations

Relations and reusable components can be selected through the generated schema when the active content model exposes them.

Cursor pagination

Generated collection roots expose nodes, totalCount, pageInfo, bounded first values, and after cursors.

A Stable Query

Query a page and navigation in one document

This example uses only stable fields defined by the current public schema. Variables carry the path and locale so the document remains reusable and reviewable.

Custom roots such as article depend on the tenant’s active model. Inspect or export the schema before selecting those fields.

PageNavigation.graphqlCurrent stable schema
query PageNavigation($path: String!, $locale: String) {
  page(path: $path, locale: $locale) {
    id
    name
    slug
    locale
  }
  navigation(locale: $locale) {
    id
    name
    url
    openInNewTab
    children {
      id
      name
      url
    }
  }
}
lib/contoprix-graphql.ts
import { createContoprixGraphQLClient } from "@contoprix/graphql-client";

export const graph = createContoprixGraphQLClient({
  endpoint: process.env.CONTOPRIX_BASE_URL!,
  auth: {
    type: "deliveryKey",
    deliveryKey: process.env.CONTOPRIX_GRAPHQL_KEY!,
  },
  locale: "en",
  timeout: 10_000,
});

const page = await graph.getPage({ path: "/about" });

Frontend Integration

Keep GraphQL credentials and queries on the server

The current @contoprix/graphql-client package appends the endpoint path, sends delivery-key or bearer authentication, supports timeouts, and distinguishes transport failures from GraphQL response errors.

A GraphQL delivery key needs graphql:read. Use request() for strict error handling or requestWithErrors() only when the UI has a reviewed partial-data policy.

GraphQL with Next.js
GraphQL or REST

Choose the simpler contract for each screen

GraphQL can make complex response shapes explicit. REST often remains easier to cache, inspect, and operate for straightforward delivery requests.

Decision areaREST and standard SDKGraphQL
Simple page or entry lookupUsually the shortest pathUseful, but may add query tooling without changing the result
One view combines several content shapesMay require multiple endpointsCan select one reviewed response shape
RelationsUse delivered expansions or additional requestsSelect relation fields exposed by the tenant schema
HTTP cachingNatural URL-based GET behaviorRequires a query-aware application or server cache policy
ErrorsPrimarily HTTP and endpoint response semanticsA response may contain both data and field-level errors
Schema toolingSDK and endpoint DTOsSchema export, generated types, and query maintenance

Read the balanced technical comparison in REST vs GraphQL for Headless CMS Content Delivery.

Developer Workflow

Treat the schema and query as maintained application contracts

A durable GraphQL integration includes model review, generated types, bounded queries, explicit error behavior, and cache refresh after publication.

  1. 01

    Model

    Define and enable content types, component types, fields, and relations in Contoprix.

  2. 02

    Inspect

    Use Graph Playground in development or pull the protected schema export with the CLI.

  3. 03

    Generate

    Generate TypeScript output for the current tenant schema instead of guessing model fields.

  4. 04

    Query

    Write bounded documents with variables and request only the fields the server-rendered view needs.

  5. 05

    Handle

    Distinguish transport failures from GraphQL errors and decide whether partial data is safe.

  6. 06

    Refresh

    Connect publication to the application cache policy so new published content reaches visitors.

Inspect, do not assume

Generated content fields differ by tenant and model revision.

Separate scopes

GraphQL delivery and schema export use separate least-privilege scopes.

Bound the query

Use variables, cursor pagination, reviewed depth, and intentional error handling.

Build with the Current Contract

Inspect the schema, run a stable query, then integrate it at the server boundary.

Start in the GraphQL guide or Graph Playground. For conventional page and content requests, compare the REST delivery API and SDK first.