KeystoneJS is an open-source headless CMS and GraphQL API framework built by the team at Thinkmill. Define your schema in TypeScript, and Keystone generates a GraphQL API, admin UI, and database migrations automatically.
What Makes KeystoneJS Special?
- TypeScript-first — schema defined in code
- Auto-generated GraphQL — complete CRUD API from schema
- Admin UI — customizable, auto-generated
- Access control — field-level security
- Document field — structured rich text with custom blocks
The Hidden API: Schema-Driven GraphQL
import { config, list } from '@keystone-6/core';
import { text, integer, relationship, timestamp, select, image } from '@keystone-6/core/fields';
import { document } from '@keystone-6/fields-document';
export default config({
db: { provider: 'postgresql', url: process.env.DATABASE_URL },
lists: {
Post: list({
access: { operation: { query: () => true, create: isAdmin, update: isAdmin, delete: isAdmin } },
fields: {
title: text({ validation: { isRequired: true } }),
slug: text({ isIndexed: 'unique' }),
status: select({
options: [
{ label: 'Draft', value: 'draft' },
{ label: 'Published', value: 'published' }
],
defaultValue: 'draft'
}),
content: document({
formatting: true,
dividers: true,
links: true,
layouts: [['1fr', '1fr']]
}),
author: relationship({ ref: 'User.posts', many: false }),
tags: relationship({ ref: 'Tag.posts', many: true }),
publishedAt: timestamp(),
heroImage: image({ storage: 'local_images' })
},
hooks: {
resolveInput: ({ resolvedData }) => {
if (resolvedData.title) {
resolvedData.slug = resolvedData.title.toLowerCase().replace(/\s+/g, '-');
}
return resolvedData;
}
}
}),
Tag: list({
fields: {
name: text({ validation: { isRequired: true }, isIndexed: 'unique' }),
posts: relationship({ ref: 'Post.tags', many: true })
}
})
}
});
This generates:
query {
posts(where: { status: { equals: "published" } }, orderBy: { publishedAt: desc }, take: 10) {
id title slug status publishedAt
author { name }
tags { name }
content { document }
}
}
Quick Start
npm create @keystone-6/app
cd my-app && npm run dev
# Admin: localhost:3000 | GraphQL: localhost:3000/api/graphql
Why Teams Choose Keystone
A developer shared: "We tried Strapi, Directus, and Keystone. Keystone won because the schema IS TypeScript — no clicking through GUIs, no YAML files. Our schema is version-controlled, reviewed in PRs, and fully type-safe."
Building content platforms? Email spinov001@gmail.com or check my toolkit.
What headless CMS do you prefer? Code-first or GUI-first?
Top comments (0)