Sign inSign up

crumbleerp/clarity

By crumbleerp

•Updated 3 months ago

GROQ-powered self-hosted headless CMS

Image
Content management system
0

1.1K

crumbleerp/clarity repository overview

Clarity CMS

⁠Clarity

Open-source, self-hosted headless CMS with a Sanity-compatible API.

MIT License Docker Pulls npm


Tip

Clarity is in **alpha** and under active development. APIs and features may change. Contributions and feedback are welcome!

Clarity is a self-hosted CMS that gives you a Sanity-compatible API on top of your own PostgreSQL database. Query your content with GROQ, mutate documents through a REST API, and manage everything from a built-in dashboard — no vendor lock-in, no cloud dependency.

⁠Why Clarity?
  • Self-Hosted — run on your own infrastructure, no cloud dependency
  • Own your data — everything lives in your PostgreSQL instance
  • Sanity-compatible API — drop-in replacement for Sanity's query and mutation endpoints
  • GROQ queries — filter, project, and order content with the same query language
  • Built-in dashboard — schema editor, document editor, media library, GROQ playground
  • S3 media storage — upload images and files to any S3-compatible provider
  • Multi-dataset — manage multiple datasets (e.g. production, staging) from one instance
  • One-click Sanity import — migrate your existing project with full asset transfer

⁠Quick Start

Copy docker-compose.yaml to your server and adjust the values:

services:
  app:
    image: crumbleerp/clarity:latest
    container_name: clarity-app
    ports:
      - "3000:3000"
    environment:
      NUXT_DATABASE_URL: postgresql://clarity:clarity@postgres:5432/clarity
      NUXT_PUBLIC_DATASET: production
      NUXT_ROOT_USERNAME: admin
      NUXT_ROOT_PASSWORD: admin
      NUXT_SESSION_SECRET: some-random-secret-at-least-32-chars-long
      NUXT_PUBLIC_API_BASE_URL: "https://example.com"
      NUXT_S3_ENDPOINT: https://s3.example.com
      NUXT_S3_REGION: us-east-1
      NUXT_S3_BUCKET: clarity-bucket
      NUXT_S3_ACCESS_KEY: access-key
      NUXT_S3_SECRET_KEY: secret-key
      NUXT_S3_PUBLIC_URL: https://cdn.example.com
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped

  postgres:
    image: postgres:17-alpine
    container_name: clarity-postgres
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_USER: clarity
      POSTGRES_PASSWORD: clarity
      POSTGRES_DB: clarity
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U clarity -d clarity"]
      interval: 5s
      timeout: 5s
      retries: 10
    restart: unless-stopped

volumes:
  postgres-data:

Then start:

docker compose up -d

Open your instance, log in with the credentials you set above, and you're ready to go.

⁠Import data from Sanity

The fastest way to populate Clarity is to import from an existing Sanity project.

In the dashboard go to Settings → Import from Sanity and fill in:

FieldWhere to find it
Project IDsanity.io → your project → Settings
Datasetusually production
Read Tokensanity.io → API → Tokens → add a token with View access

Click Import — all documents, schemas, and assets (images/files) will be migrated in the background.

⁠Connect with JS client

Install the client:

npm install @crumbleerp/clarity
import { createClient, groq } from '@crumbleerp/clarity'

const client = createClient({
  endpoint: 'https://cms.example.com',  // your Clarity instance
  dataset: 'production'
})

// Fetch all posts
const posts = await client.fetch(groq`*[_type == 'post'] | order(publishedAt desc)[0...10]`)

// Fetch with parameters
const post = await client.fetch(
  groq`*[_type == 'post' && slug.current == $slug][0]`,
  { slug: 'hello-world' }
)

console.log(post.title)

The client works with any framework — Next.js, Nuxt, SvelteKit, Astro, or plain Node.js.


⁠Deploy

⁠Docker (without Compose)
docker run -d \
  -p 3000:3000 \
  -e NUXT_DATABASE_URL=postgresql://user:pass@host:5432/clarity \
  -e NUXT_ROOT_USERNAME=admin \
  -e NUXT_ROOT_PASSWORD=change-me \
  -e NUXT_SESSION_SECRET=your-random-secret-at-least-32-chars \
  crumbleerp/clarity:latest
⁠Environment Variables
VariableRequiredDefaultDescription
NUXT_DATABASE_URLYes—PostgreSQL connection string
NUXT_DATASETNoproductionDefault dataset name
NUXT_ROOT_USERNAMENoadminRoot user login
NUXT_ROOT_PASSWORDNoadminRoot user password
NUXT_NUXT_SESSION_SECRETYes—Session encryption secret (min 32 chars)
NUXT_BASE_URLNo—Public API base URL (empty = same origin)
NUXT_S3_ENDPOINTNo—S3-compatible storage endpoint
NUXT_S3_REGIONNous-east-1S3 region
NUXT_S3_BUCKETNo—S3 bucket name
NUXT_S3_ACCESS_KEYNo—S3 access key
NUXT_S3_SECRET_KEYNo—S3 secret key
NUXT_S3_PUBLIC_URLNo—Public URL for serving uploaded assets

⁠Schemas

Schemas define the structure of your documents. You can manage them from the dashboard or through the API.

⁠Dashboard

Navigate to Settings → Schemas and define your types using the built-in JSON editor:

[
  {
    "name": "post",
    "title": "Blog Post",
    "schema_type": "document",
    "fields": [
      { "name": "title", "type": "string", "title": "Title", "required": true },
      { "name": "slug", "type": "slug", "title": "Slug" },
      { "name": "body", "type": "markdown", "title": "Body" },
      { "name": "publishedAt", "type": "datetime", "title": "Published At" },
      { "name": "author", "type": "reference", "title": "Author", "referenceTo": ["author"] }
    ]
  }
]
⁠Supported field types
TypeDescription
stringSingle-line text
textMulti-line text
numberNumeric value
booleanToggle switch
urlURL input
emailEmail input
dateDate picker
datetimeDate & time picker
colorColor picker
slugURL-friendly slug
markdownRich text (Markdown)
htmlRich text (HTML)
referenceReference to another document
imageImage upload / media selector
fileFile upload / media selector
objectNested object with its own fields
arrayList of items
⁠JavaScript client

Use the @crumbleerp/clarity package to define schemas in code:

import { createClient, defineType, defineField, groq } from '@crumbleerp/clarity'

const client = createClient({
  endpoint: 'https://your-clarity-instance.com',
  dataset: 'production'
})

// Define a schema
const post = defineType({
  name: 'post',
  title: 'Blog Post',
  fields: [
    defineField({ name: 'title', type: 'string', title: 'Title' }),
    defineField({ name: 'body', type: 'markdown', title: 'Body' })
  ]
})

// Query with GROQ
const posts = await client.fetch(groq`*[_type == 'post'] | order(publishedAt desc)`)

⁠Sanity Compatibility

Clarity implements Sanity's public API for queries and mutations, making it a drop-in replacement for many use cases.

⁠What's compatible
FeatureStatus
GET /v1/data/query/{dataset}Supported
POST /v1/data/mutate/{dataset}Supported
GROQ filtering, projections, orderingSupported
Parameterized queries ($param)Supported
create, createIfNotExists, createOrReplaceSupported
patch with set / unsetSupported
delete mutationSupported
System fields (_id, _type, _rev, _createdAt, _updatedAt)Supported
Document referencesSupported
Image & file assetsSupported
Multi-datasetSupported
⁠What's different
AspectSanityClarity
HostingCloud-managedSelf-hosted
DatabaseProprietaryPostgreSQL
AuthToken-basedSession-based (dashboard)
PricingPer-dataset, per-usageFree (MIT)
CDN / image pipelineBuilt-inS3 + your own CDN
Real-time collaborationYesNo
Vision (GROQ playground)Studio pluginBuilt-in dashboard
⁠Migration from Sanity

Clarity includes a one-click import tool. Go to Settings → Import from Sanity and provide:

  • Project ID
  • Dataset name
  • Read token

All documents, schemas, and assets will be migrated automatically with background job tracking.


⁠API Reference

⁠Query content
GET /v1/data/query/{dataset}?query=*[_type == "post"]
⁠Mutate content
POST /v1/data/mutate/{dataset}
Content-Type: application/json

{
  "mutations": [
    { "create": { "_type": "post", "title": "New Post" } }
  ]
}
⁠Dashboard API
MethodEndpointDescription
POST/api/auth/loginAuthenticate
GET/api/auth/meCurrent user
GET/api/documentsList documents
POST/api/documentsCreate document
GET/api/documents/:idGet document
PUT/api/documents/:idUpdate document
DELETE/api/documents/:idDelete document
GET/api/schemasList schemas
POST/api/schemasCreate/update schemas
DELETE/api/schemas/:nameDelete schema
GET/api/mediaList media assets
POST/api/uploadUpload file

⁠Useful Resources


⁠License

MIT⁠

Tag summary

Content type

Image

Digest

sha256:4ff807752…

Size

66.5 MB

Last updated

3 months ago

docker pull crumbleerp/clarity