Skip to main content
StormyCMS

GraphQL Mutations

Mutations create, update, and delete content. Content mutations require a user JWT in addition to your site credentials — they represent editor actions, not anonymous API calls.

Authentication

headers: {
'Content-Type': 'application/json',
'x-client-id': 'YOUR_CLIENT_ID',
'x-client-secret': 'YOUR_CLIENT_SECRET',
'Authorization': 'Bearer YOUR_JWT'
}

Get a JWT by exchanging the signed-in user's session token with mintJwt — or let @stormycms/core's client do it automatically from the session cookie. See API Reference → Authentication for the full flow.

Page Mutations

Create a Page

mutation CreatePage(
$slug: String!
$metadata: metadataInput!
$components: [componentInput!]!
$layoutId: ID!
$createdAt: String!
$updatedAt: String!
) {
createPage(
slug: $slug
metadata: $metadata
components: $components
layoutId: $layoutId
createdAt: $createdAt
updatedAt: $updatedAt
) {
id
slug
metadata {
title
description
keywords
}
layoutId
}
}

Variables:

{
"slug": "about-us",
"metadata": {
"title": "About Us",
"description": "Learn about our team",
"keywords": ["about", "team"]
},
"components": [
{
"name": "Heading",
"props": [
{ "name": "text", "value": "About Us" },
{ "name": "level", "value": "h1" }
]
},
{
"name": "Text",
"props": [{ "name": "content", "value": "We build things." }]
}
],
"layoutId": "LAYOUT_ID",
"createdAt": "2026-07-06T00:00:00.000Z",
"updatedAt": "2026-07-06T00:00:00.000Z"
}

Component name values must match exports in your project's CMS export map (see Components & Schema) or they won't render.

Update a Page

mutation UpdatePage(
$id: ID!
$slug: String!
$metadata: metadataInput!
$components: [componentInput!]!
$layoutId: ID!
$updatedAt: String!
) {
updatePage(
id: $id
slug: $slug
metadata: $metadata
components: $components
layoutId: $layoutId
updatedAt: $updatedAt
) {
id
slug
metadata {
title
}
updatedAt
}
}

Updates replace the page's component tree with the provided components array.

Delete a Page

mutation DeletePage($id: ID!) {
deletePage(id: $id) {
id
}
}

Layout Mutations

Create a Layout

mutation CreateLayout($name: String!, $components: [componentInput!]!, $createdAt: String!, $updatedAt: String!) {
createLayout(name: $name, components: $components, createdAt: $createdAt, updatedAt: $updatedAt) {
id
name
outletId
parentLayoutId
childLayoutId
}
}

Include an Outlet component in components to mark where page content should render.

Update a Layout

mutation UpdateLayout(
$id: ID!
$name: String!
$components: [componentInput!]!
$parentLayoutId: ID
$updatedAt: String!
) {
updateLayout(id: $id, name: $name, components: $components, parentLayoutId: $parentLayoutId, updatedAt: $updatedAt) {
id
name
parentLayoutId
}
}

Set parentLayoutId to nest this layout inside another (e.g. a "Blog" layout inside the site-wide layout).

Delete a Layout

mutation DeleteLayout($id: ID!) {
deleteLayout(id: $id) {
id
}
}

Media Mutations

Upload the file to your own S3-compatible storage first (the boilerplate admin handles this), then record it. These mutations need your site credentials (x-client-id / x-client-secret) just like content reads; the official Next.js admin client also passes the editor JWT, but the API authorizes the request via the site API key.

mutation CreateMedia($type: String!, $url: String!, $name: String!, $metadata: Json!) {
createMedia(type: $type, url: $url, name: $name, metadata: $metadata) {
id
type
url
name
}
}
mutation UpdateMedia($id: ID!, $name: String) {
updateMedia(id: $id, name: $name) {
id
name
}
}
mutation DeleteMedia($id: ID!) {
deleteMedia(id: $id) {
id
}
}

Auth Mutations

Used by the auth flow itself (wired automatically by @stormycms/next):

mutation ExchangeAuthCode($code: String!, $clientId: String!) {
exchangeAuthCode(code: $code, clientId: $clientId) {
sessionToken
user {
id
username
email
}
}
}
mutation GetJWTToken($sessionToken: String!) {
mintJwt(sessionToken: $sessionToken) {
jwt
expiresIn
}
}

Using the Typed Client

import { StormyCMSClient } from '@stormycms/core';
const client = new StormyCMSClient();
const jwt = await client.getJWTToken(cookieHeader);
const now = new Date().toISOString();
const page = await client.createPage(jwt, {
slug: 'about-us',
metadata: { title: 'About Us', description: '', keywords: [] },
components: [],
layoutId: 'LAYOUT_ID',
createdAt: now,
updatedAt: now,
});

Next Steps

Last updated: 7/9/26, 6:42 AM

StormyCMSThe headless CMS where you own the management panel
Community
StormyCMS