# Easy CMS **The embedded, code-first headless CMS for Nuxt and Next.js.** A headless CMS that lives inside your Nuxt or Next.js app: the content model is TypeScript in your repository, the admin and APIs come with it, and there is no extra server to run. [![npm](https://img.shields.io/npm/v/@easy-cms/core?label=npm&color=2f6f5e)](https://www.npmjs.com/package/@easy-cms/core) [![Downloads](https://img.shields.io/npm/dm/@easy-cms/core?label=downloads&color=2f6f5e)](https://www.npmjs.com/package/@easy-cms/core) [![CI](https://github.com/maritonx/easy-cms/actions/workflows/ci.yml/badge.svg)](https://github.com/maritonx/easy-cms/actions/workflows/ci.yml) [![Coverage](https://codecov.io/gh/maritonx/easy-cms/graph/badge.svg)](https://codecov.io/gh/maritonx/easy-cms) [![Commit activity](https://img.shields.io/github/commit-activity/m/maritonx/easy-cms?color=555)](https://github.com/maritonx/easy-cms/commits/main) [![Docs](https://img.shields.io/badge/docs-EN%20%7C%20TH-2f6f5e)](https://easycms.dev/docs) [![Node](https://img.shields.io/badge/node-%E2%89%A522.12-555)](https://nodejs.org) [![License: MIT](https://img.shields.io/badge/license-MIT-555)](LICENSE) [Website](https://easycms.dev) · [Documentation](https://easycms.dev/docs) · [เอกสารภาษาไทย](https://easycms.dev/th/docs) · [Getting started](https://easycms.dev/docs/getting-started) · [Examples](#examples) · [Sponsor](https://github.com/sponsors/maritonx) [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fmaritonx%2Feasy-cms%2Ftree%2Fmain%2Ftemplates%2Fnext-starter&project-name=easy-cms&repository-name=easy-cms&env=EASY_CMS_SETUP_CODE&envDescription=A+code+you+choose%3A+you+type+it+to+create+the+first+admin+at+%2Fadmin&envLink=https%3A%2F%2Feasycms.dev%2Fdocs%2Fone-click-deploy&stores=%5B%7B%22type%22%3A%22integration%22%2C%22integrationSlug%22%3A%22neon%22%2C%22productSlug%22%3A%22neon%22%2C%22protocol%22%3A%22storage%22%7D%2C%7B%22type%22%3A%22blob%22%2C%22access%22%3A%22public%22%7D%5D) [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/maritonx/easy-cms&create_from_path=templates/next-starter)
The Easy CMS admin dashboard: content at a glance, recently edited pages and drafts to review
More screenshots | | | |---|---| | Editing a post: fields in tabs, with its status, category and tags in the side panel | Live preview: the real page beside the form, updated as you type | | Editing, with a side panel | Live preview of unsaved changes | | Posts on a month calendar, coloured by category, with today's posts in the card beside it | A role's permissions, ticked per collection and action | | A calendar of posts by publish date | Roles, set from the admin |
## Why Easy CMS - **Runs inside your app.** A Nuxt module or Next.js route handlers add the admin at `/admin` and the API at `/api/cms`. One deployment, one database (yours, with prefixed tables). - **Code-first and typed.** Collections, fields and access rules are TypeScript. The Local API infers document types from the config, so queries are typed without a build step. - **Any frontend, too.** Using Vite, React, Vue, a mobile app or a static site? Run the same CMS as a [standalone server](https://easycms.dev/docs/standalone) and use its REST API. - **An admin editors like**, in English and Thai: drafts, version history, live preview, scheduled publishing, a calendar, blocks, translations, a media library and a light and dark theme. - **Secure by default:** [self-reviewed](docs/security/asvs-l1.md) against OWASP ASVS level 1. Common passwords are refused, cookies are `__Host-` and HSTS is on in production, unreadable documents answer 404, and the audit log is signed against tampering. - **Official plugins** for SEO, forms, redirects, nested pages, a shop, GraphQL, several sites in one CMS (multi-tenant) and AI assistants (MCP). > [!NOTE] > **Stable since 1.0.** Breaking changes come only in a major release, with an upgrade guide; > renamed APIs keep working until the next major, with a warning. > [Versions and deprecations](https://easycms.dev/docs/versioning) says what is covered (the shop, > GraphQL and MCP plugins are still experimental), and the > [changelog](https://easycms.dev/changelog) what each release added. ## When to use it **A good fit** if you build sites with Nuxt or Next.js, or want a CMS on your own server for another frontend; if you want the content model in code, reviewed and deployed like the rest of the app; and if one deployment and one database is what you want to run. **Look elsewhere** if you want a hosted service with nothing to deploy, if people who don't write code should design the content model, or if you need a large marketplace of third-party plugins: so far there are the official ones. ## Quick start To try it without installing anything, use the **Deploy** buttons above: a blog with its admin on Vercel or Netlify, with a database and file storage made for you ([one-click deploy](https://easycms.dev/docs/one-click-deploy)). In a Nuxt 4 or Next.js 15+ project: ```bash npm create easy-cms@latest # or: pnpm create easy-cms · yarn create easy-cms · bun create easy-cms npm run dev # then open http://localhost:3000/admin ``` `create-easy-cms` installs the packages with your package manager, writes `easy-cms.config.ts` with a sample collection and a secret in `.env`, and wires up the framework. Describe your content in the config: ```ts // easy-cms.config.ts import { defineConfig } from '@easy-cms/core' import { sqlite } from '@easy-cms/db-sqlite' export default defineConfig({ secret: process.env.EASY_CMS_SECRET!, db: sqlite({ url: 'file:./cms.db' }), collections: [ { slug: 'posts', drafts: true, fields: [ { name: 'title', type: 'text', required: true }, { name: 'slug', type: 'slug', from: 'title' }, { name: 'body', type: 'richText' }, ], }, ], }) ``` Then read it in your pages, fully typed: ```ts // Nuxt: server/api/posts.get.ts export default defineEventHandler(async () => { const cms = await useEasyCMS() return cms.find('posts', { sort: '-createdAt', limit: 10 }) }) ``` Next.js uses `getEasyCMS(config)` in Server Components; any other client uses REST at `/api/cms/posts`. **No Nuxt or Next.js?** Run the same command in an empty directory to get a standalone server: ```bash npm create easy-cms@latest my-cms cd my-cms && npm run dev # http://localhost:4000/admin ``` ## Features **Content modeling** - 15 field types: text, rich text (Tiptap), number, date, select, relationship, upload, array, group, blocks, JSON and more, with validation and per-field access - Uploads with several files and drag-to-order (galleries), limited to the file types you allow: images, PDF, Word, Excel, PowerPoint, OpenDocument, CSV, audio, video and zip, detected from their contents - Collections and globals, drafts and publishing, hooks - Localization: one value per language, translation status in the lists - Version history with restore, and drafts kept apart from the published version **Admin** - A menu with groups that fold, badges for what needs attention, and a command palette (⌘K) that finds documents and runs actions - Lists with search, filters, columns, bulk actions and tree views; edit forms with tabs, sections, rows, fields shown on conditions, and a side panel - Live preview of unsaved changes on your real pages - Scheduled publish and unpublish in the admin's time zone, and statuses that say what is pending: **Scheduled · date**, **Unpublished changes** - A calendar for documents with dates (posts by publish date, events): month, week and day views, a card with the day's documents, and drag or **Move to…** another day, with Undo - A media library with folders (and who may use each), many files uploaded at once with their progress, icons by file type, a grid view, and previews: images, audio and video players, PDFs, text and CSV - A dashboard that tells admins what needs attention: failed webhooks, stuck emails, late scheduled publishing - Roles from the admin: tick what each role may do per collection, page and field, or on its own documents only, no code - An audit log of who changed which fields, sign-ins and admin actions, signed against tampering - English and Thai interface, light and dark themes, works on phones **APIs** - Typed Local API (fields that plugins add included), REST API with `where` queries, a GraphQL API (plugin), and generated types for frontends in other repositories - Users and roles, function-based access rules per collection, document and field; forgotten passwords and invitations by email; single sign-on with Google, Microsoft, GitHub or any OpenID Connect provider - Site members (customers, subscribers) who sign up on your site, kept out of the admin - API keys with per-collection permissions, signed webhooks with retries, email with retries **Data and operations** - SQLite (libSQL) or Postgres (postgres.js or PGlite) through Drizzle - Schema push in development, reviewed migration files in production - Uploads on disk, S3, Cloudflare R2, MinIO, Vercel Blob or Netlify Blobs, also from links (the server downloads them) - One-click deploy to Vercel or Netlify, with a database and file storage - Database backups on a schedule or by hand from the admin, downloadable, optionally encrypted (AES-256-GCM) - `easy-cms` CLI: migrations, backups, copying between databases, scheduled jobs - Upgrades tested in CI: databases made by older releases migrate to the current one **SEO and AI** - Meta fields with a search preview, sitemaps, robots.txt, hreflang and JSON-LD - `llms.txt`, Markdown versions of pages and AI crawler rules - An MCP server so AI assistants can read and draft content with a limited API key ## Official plugins | Plugin | What it adds | Guide | |---|---|---| | [`@easy-cms/plugin-seo`](packages/plugin-seo) | Meta fields, search preview, sitemap, robots.txt, structured data, llms.txt | [SEO](https://easycms.dev/docs/seo) | | [`@easy-cms/plugin-form-builder`](packages/plugin-form-builder) | Forms built in the admin, submissions with an overview and a dashboard panel, email notifications, spam protection, `` | [Forms](https://easycms.dev/docs/forms) | | [`@easy-cms/plugin-redirects`](packages/plugin-redirects) | Redirects managed in the admin, automatic redirects when a page moves | [Redirects](https://easycms.dev/docs/redirects) | | [`@easy-cms/plugin-notify`](packages/plugin-notify) | Telegram messages to admins when a form is sent, an order comes in or something fails | [Notifications](https://easycms.dev/docs/notifications) | | [`@easy-cms/plugin-ai`](packages/plugin-ai) | Claude, GPT, Gemini or an OpenAI-compatible server for the admin's AI features, with daily limits and usage | [AI](https://easycms.dev/docs/ai) | | [`@easy-cms/plugin-social`](packages/plugin-social) (experimental) | Write a post once and send it to several channels (webhooks to Make, n8n, Zapier), now or scheduled, with a state per channel | [Social posts](https://easycms.dev/docs/social) | | [`@easy-cms/plugin-nested-docs`](packages/plugin-nested-docs) | Pages inside pages: parents, full paths, breadcrumbs, a tree in the admin | [Nested pages](https://easycms.dev/docs/nested-docs) | | [`@easy-cms/plugin-graphql`](packages/plugin-graphql) (experimental) | GraphQL API: queries and mutations for every collection and global, with your access rules | [GraphQL](https://easycms.dev/docs/graphql) | | [`@easy-cms/plugin-mcp`](packages/plugin-mcp) (experimental) | Model Context Protocol server for AI assistants | [MCP](https://easycms.dev/docs/mcp) | | [`@easy-cms/plugin-multi-tenant`](packages/plugin-multi-tenant) | Several sites or clients in one CMS: content, members, roles and settings per tenant, a tenant switcher | [Multi-tenant](https://easycms.dev/docs/multi-tenant) | | [`@easy-cms/plugin-ecommerce`](packages/plugin-ecommerce) (experimental) | A shop: products and variants, prices in several currencies, carts, checkout with Stripe or bank transfer (unpaid orders expire and return their stock), orders, stock, customer accounts, React and Vue hooks | [Shop](https://easycms.dev/docs/ecommerce) | Experimental plugins share the version number but may still change in a minor release, even after 1.0, until they are declared stable. Plugins are functions over your config: write your own with fields, endpoints, admin components, admin pages, dashboard panels and CLI commands. See [Plugins](https://easycms.dev/docs/plugins). Packages can also add field types, such as `color` from [`@easy-cms/fields`](packages/fields): see [Custom field types](https://easycms.dev/docs/field-types). ## Packages
All packages (they share one version) | Package | | |---|---| | [`@easy-cms/core`](packages/core) | Config, Local API, REST handler, auth, access control, hooks, localization, versions, webhooks | | [`@easy-cms/nuxt`](packages/nuxt) | Nuxt 4 module: REST API, admin, typed `useEasyCMS()` | | [`@easy-cms/next`](packages/next) | Next.js adapter: route handlers, typed `getEasyCMS()` | | [`easy-cms`](packages/cli) | CLI: migrations, types, users, backups, standalone `serve` | | [`create-easy-cms`](packages/create-easy-cms) | Adds Easy CMS to a project, or creates a standalone server | | [`@easy-cms/db-sqlite`](packages/db-sqlite) | SQLite / libSQL database adapter | | [`@easy-cms/db-postgres`](packages/db-postgres) | Postgres adapter (postgres.js or PGlite) | | [`@easy-cms/storage-s3`](packages/storage-s3) | Uploads on S3, Cloudflare R2 or MinIO | | [`@easy-cms/storage-vercel-blob`](packages/storage-vercel-blob) | Uploads on Vercel Blob | | [`@easy-cms/storage-netlify-blobs`](packages/storage-netlify-blobs) | Uploads on Netlify Blobs | | [`@easy-cms/email-smtp`](packages/email-smtp) | Email over SMTP | | [`@easy-cms/auth-oauth`](packages/auth-oauth) | Single sign-on: Google, Microsoft, GitHub, OpenID Connect | | [`@easy-cms/richtext`](packages/richtext) | Rich text to safe HTML or Markdown | | [`@easy-cms/fields`](packages/fields) | More field types: `color`, with a picker and swatches | | [`@easy-cms/admin`](packages/admin) | The admin UI (installed by the adapters) | | [`@easy-cms/drizzle`](packages/drizzle) | Shared database layer (installed by the database adapters) |
## Examples | Example | | |---|---| | [`examples/nuxt-blog`](examples/nuxt-blog) | Nuxt 4 blog on SQLite, with every official plugin | | [`examples/next-blog`](examples/next-blog) | Next.js 16 blog on Postgres (PGlite locally) | | [`examples/standalone`](examples/standalone) | Standalone server with a plain HTML frontend on another origin | | [`examples/shop`](examples/shop) | Next.js 16 shop: products, cart, checkout (bank transfer, or Stripe), customer accounts | | [`examples/multi-tenant`](examples/multi-tenant) | Two brands in one CMS, each with its own content, media and members | ## Requirements - Node.js 22.12 or later (22.19 or later with Nuxt) - Nuxt 4, Next.js 15 or later (App Router), or no framework (standalone) - SQLite or Postgres - npm, pnpm, Yarn (node-modules) or Bun to install ## Contributing Issues and pull requests are welcome. [CONTRIBUTING.md](CONTRIBUTING.md) explains how to build, test and propose changes; [docs/DESIGN.md](docs/DESIGN.md) and the [architecture decisions](docs/adr) explain why things are the way they are. Please report security issues privately, as described in [SECURITY.md](SECURITY.md). ## Sponsors Easy CMS is built in spare time. If it saves you or your team time, consider [sponsoring its development](https://github.com/sponsors/maritonx): sponsorship pays for new features, docs in English and Thai, and faster fixes. Sponsors at $5 a month or more are listed here, and company sponsors also get their logo on [the website](https://easycms.dev). [![Sponsor Easy CMS](https://img.shields.io/badge/sponsor-%E2%9D%A4-2f6f5e?logo=githubsponsors)](https://github.com/sponsors/maritonx) ### Founding sponsors The first 10 sponsors, at any tier, are listed here permanently, even if they stop sponsoring later. ## License [MIT](LICENSE)