1.0Easy CMS 1.0 is out: stable from here on

Your Next.js app is already a CMS.

Easy CMS runs inside your Next.js or Nuxt app. Define content in TypeScript, and you get an admin at /admin, a typed API and REST, on one deployment and your own database.

$npm create easy-cms@latest
Or deploy a starter in one click: Deploy to Vercel Deploy to NetlifyWhat you get
MIT licensedNext.js 15+ · NuxtAdmin in English & ไทย
localhost:3000/admin
The Easy CMS admin dashboardThe Easy CMS admin dashboard
app/page.tsxServer Component
const cms = await getEasyCMS(config)
const { docs } = await cms.find('posts')
// docs: Post[], typed from your config
Runs with
  • Next.js 15+
  • Nuxt
  • PostgreSQL
  • SQLite · Turso
  • PGlite
  • S3 · R2 · MinIO
  • Vercel · Netlify
Embedded, not hosted

No second server to run, pay for or keep in sync.

A typical headless CMS is another service with its own database and API keys. Easy CMS is an npm package your app mounts, so content ships with the code that renders it.

A hosted headless CMS

Two apps, two databases

Your Next.js app
pagesfetch()
CMS serviceseparate deploy
CMS databasenot yours
  • Schema lives in a web UI, not in your repo
  • Types generated in a separate step
  • A network hop on every page render
Easy CMS

One app, one database

Your Next.js app
pages → getEasyCMS()/admin/api/cms
@easy-cms/next@easy-cms/core
Your databasePostgres or SQLite · only ecms_ tables
  • Content model in easy-cms.config.ts, reviewed in PRs
  • Types come straight from the config, no build step
  • Deploys wherever your app already runs
Code-first

Three files and your app has a CMS.

Describe collections and fields in TypeScript. The admin forms, validation, access rules and the typed API are built from that one file.

import { defineConfig } from '@easy-cms/core'
import { postgres } from '@easy-cms/db-postgres'
import { seoPlugin } from '@easy-cms/plugin-seo'

export default defineConfig({
  secret: process.env.EASY_CMS_SECRET!,
  db: postgres({ url: process.env.DATABASE_URL! }),
  localization: { locales: ['en', 'th'], defaultLocale: 'en' },
  collections: [
    {
      slug: 'posts',
      drafts: true, versions: true, schedule: true,
      useAsTitle: 'title',
      fields: [
        { name: 'title', type: 'text', required: true, localized: true },
        { name: 'slug', type: 'slug', from: 'title' },
        { name: 'body', type: 'richText', localized: true },
      ],
    },
  ],
  plugins: [seoPlugin({ collections: ['posts'] })],
})
Built in

What editors expect, what developers can review.

Drafts and version history

Edit a published post without touching the live page. Compare versions and restore any of them.

Live preview

Your real page sits next to the form and updates as editors type, before anything is published.

Localized content

One value per language, with translation status in every list. The admin speaks English and Thai.

Roles and single sign-on

Tick what each role may do in the admin, down to fields. Sign in with Google, Microsoft or GitHub.

A media library with folders

Folders, many files at once, private files with signed links, and storage on S3, R2 or Vercel Blob.

Audit log and backups

A signed record of who changed what, and database backups you start or schedule from the admin.

Scheduled publishing

Publish or unpublish at a set time. Due jobs run every minute on the server you already have.

SEO out of the box

Sitemaps, hreflang, JSON-LD and llms.txt from the content you already have.

Typed API, REST and GraphQL

A typed Local API in your server code, REST for any client, and GraphQL and MCP as plugins.

Measured at scale

Fast at a million documents.

Every night a load test runs Easy CMS against 1,000,000 posts. The times are p95: 95% of requests finish faster.

posts in one collection
1,000,000
a post by id or slug
27ms
the next page by cursor, however deep
37ms
Thai text search with a trigram index
79ms

Easy CMS 1.15 · median of 3 runs · Postgres 17 · GitHub runner, 4 cores · 20 requests at once · 28 Oct 2026

Not everything is fast yet: a page picked by number deep in the list takes seconds (use cursor instead), and so do queries inside blocks. The full results list them.

Official plugins

Add a feature with one line in plugins.

Each plugin adds its own collections, admin screens and API routes, and ships its migration. Write your own with the same hooks.

@easy-cms/plugin-seo

Meta fields, sitemaps, hreflang and JSON-LD.

seo
@easy-cms/plugin-form-builder

Editors build forms; submissions are validated, stored and exported as CSV.

forms
@easy-cms/plugin-redirects

301 to 308 redirects, created automatically when a page moves.

seo
@easy-cms/plugin-nested-docs

Pages inside pages, with paths and breadcrumbs per language.

pages
@easy-cms/plugin-multi-tenant

Several sites or clients in one CMS, each with its own members and content.

0.44
@easy-cms/plugin-ecommerce

Products, carts and checkout with Stripe, PromptPay or bank transfer.

0.46
@easy-cms/plugin-graphql

A GraphQL API with the same access rules as REST.

0.43
@easy-cms/plugin-mcp

An MCP server so AI assistants can work with your content.

ai
The admin

An admin your editors will actually like.

Generated from your config, in light and dark, English and Thai. Nothing to design or host.

your-site.com/admin
The Easy CMS admin dashboardThe Easy CMS admin dashboard
Switch the site theme to see the admin in light or dark· admin.locale: 'en' | 'th'
1.0

Stable since 1.0

  • Breaking changes come only in a major release, each with an upgrade guide.
  • A renamed API keeps working until the next major, with a warning.
  • Every change is tested against databases made by older releases, on SQLite and Postgres.
  • Security fixes reach the previous major for six months after the next one is out.
What the promise covers

Ship content with the code that renders it.

Scaffold a Next.js or Nuxt project with Easy CMS in about a minute. It is MIT licensed and runs on your own infrastructure.