@plutocms/pluto

The layerable CMS
6,441 4
Install
npm install @plutocms/pluto
Latest Version:0.17.0
Vue:3
License:MIT
Last Updated:Oct 21, 2026
Links: GitHub  ·  npm
Maintainer: ojvribeiro

Pluto CMS

A layer-based CMS powered by Nuxt.

[!WARNING] Pluto CMS is currently in alpha and at a very early stage. Expect breaking changes, incomplete features, and rough edges.

Also note: npm is still not supported due to layer dependencies not being installed correctly. It is strongly recommended to use modern package managers like pnpm or bun.

Pluto CMS is designed to be modular, extensible, and developer-friendly. Instead of a monolithic system, it lets you compose your CMS using layers. You only install what you need.

Features

  • Layer-based architecture using Nuxt Layers
  • Modern SSR + SPA hydration with Nuxt
  • TypeScript-first developer experience
  • Opt-in features instead of global plugin mutations
  • Deployment-friendly (Edge and Serverless ready)
  • Works as a full CMS or as a headless backend
  • Standalone mode: a Markdown blog stored in GitHub, with no database

Requirements

  • Node.js (22+) or Bun
  • pnpm or Bun

npm is not supported at this stage and may cause unexpected issues.

Getting started

Create a new Pluto project using the CLI:

npm create pluto@latest

# or
pnpm create pluto@latest

# or
bun create pluto@latest

This will launch an interactive setup wizard where you can:

  • Choose a database provider
  • Configure database credentials (all stored locally on your project's .env)
  • Select a starter template (blog, store, etc.)

Then:

cd your-project
bun install # or pnpm install
bun run dev # or pnpm dev

Architecture overview

Pluto CMS is built around layers, each responsible for a specific concern.

Core layer (@plutocms/pluto)

The core layer provides the foundation for your CMS:

  • <PlutoRoot>: Wraps your entire app (used in app.vue). Includes the admin navbar, NuxtLayout, NuxtLoadingIndicator, and base styles.
  • <ColorModeButton>: Light/dark mode toggle with zero configuration.
  • Built-in auth and admin layouts, the /admin route, the /admin/login page, the route guard and the admin navbar. A backend layer plugs in with an auth driver (authDriver in definePlutoExtension). See .claude/skills/admin-shell/SKILL.md.
  • <PlutoNavbarAdmin> and <PlutoNavbarAdminActions> Provide structure for injecting actions from other layers

A layer plugs into the admin UI with one function, definePlutoExtension, called from a plugin. It registers any of: an auth driver, navbar actions, sidebar nav entries, admin page metadata, dashboard widgets, and a settings panel or driver:

// app/plugins/pluto-registrations.ts
export default defineNuxtPlugin(() => {
  definePlutoExtension({
    id: 'supabase-blog',
    nav: [{ id: 'posts', label: 'Posts', icon: 'lucide:file-text', to: '/admin/posts' }],
  })
})

See .claude/skills/extension-registry/SKILL.md for the full type of each registrable thing and the ordering/dedupe rules. The old useNavbarAdmin().registerNavbar(component) and useNavbarAdminActions().addAction(component) composables still work, through a compatibility bridge, but definePlutoExtension is the current recommended way to plug in.

Backend layers

Backend layers handle data, authentication, and APIs.

Examples:

  • @plutocms/supabase Provides Supabase integration (database, auth, users, etc.)
  • Future possibilities:
    • Custom database providers (MySQL, MongoDB, etc.)
    • Other backend-as-a-service providers (Convex, Neon, Firebase, etc.)

Feature layers

Feature layers add domain-specific functionality on top of backend layers.

Examples:

  • @plutocms/supabase-shop Adds e-commerce features like:
    • Products
    • Media
    • Cart
  • Other possible layers:
    • Blog
    • Portfolio
    • Analytics
    • Payments

Feature layers depend on backend layers. For example, @plutocms/supabase-shop requires @plutocms/supabase.

Using Pluto in existing Nuxt projects

Pluto is not limited to new projects.

You can extend an existing Nuxt app using layers:

// nuxt.config.ts
export default defineNuxtConfig({
  extends: [
    '@plutocms/pluto'
    // Then add any backend or feature layers you need.
  ]
})

Styles: one Tailwind build

Your app owns the only Tailwind build. Pluto layers do not register their own. Start your CSS entry with these three imports, then add your own theme after them:

/* app/assets/css/main.css */
@import 'tailwindcss';
@import '@nuxt/ui';
@import '#build/pluto.css';

@theme {
  /* your site's tokens */
}
// nuxt.config.ts
export default defineNuxtConfig({
  css: ['~/assets/css/main.css'],
})

#build/pluto.css brings in the CSS of every Pluto layer, including the admin theme. Nuxt UI already scans the source of every layer. If your app has no Tailwind entry, Pluto uses a fallback entry. If the setup is wrong, the build prints a pluto-css warning with the fix.

The admin keeps its own palette and font. Your site's app.config colors and @theme tokens do not change the admin.

Standalone mode: a Markdown blog in GitHub

@plutocms/pluto can run on its own, with no database and no other layer. Posts are Markdown files in a GitHub repository. Editors write them in the Pluto admin, and each save is a commit. The public site reads the posts from GitHub at runtime, with a cache, so a save publishes in seconds without a new build.

The quickest start is the template:

bunx create-pluto@latest my-blog -t core-blog

Or turn it on in an existing app. It is off by default, and it refuses to run next to the supabase layer:

// nuxt.config.ts
export default defineNuxtConfig({
  extends: ['@plutocms/pluto'],
  plutoCms: {
    enabled: true,
    github: { repo: 'owner/name', branch: 'main', appSlug: 'my-blog-cms' },
    dir: 'content', // posts live in content/posts/<slug>.md
  },
})
  • Sign-in: with a GitHub App. Users with push access to the repository are editors. Commits carry the name of the editor.
  • Drafts: status: draft in the frontmatter. The public routes never show them. In a public repository, drafts are still readable on GitHub, and the admin warns about this.
  • Public pages: usePlutoCmsList('post') and usePlutoCmsItem('post', slug) read the published posts. <PlutoMarkdown :html="post.html" /> shows a post as sanitized HTML.
  • Development: set storage: 'fs' to read and write the local content/ folder. A dev server then never writes to the real repository.

The GitHub App setup, the environment variables and every option are in the template README and in .claude/skills/github-cms/SKILL.md.

Dashboard & headless usage

Although Pluto is built on Nuxt, it is not limited to Nuxt-only consumption.

  • The admin dashboard can run as a standalone app on providers like Vercel or Netlify
  • Data can be consumed via:
    • Composables (within Nuxt apps)
    • REST APIs exposed by layers

This allows you to:

  • Use Pluto as a headless CMS
  • Power web apps (any stack)
  • Power mobile apps

Why not just WordPress?

  • Modern SSR and SPA hydration via Nuxt
  • TypeScript-first experience
  • Better control through Vue composables or REST APIs
  • Deployment flexibility (Vercel, Cloudflare, Netlify, etc.)

If you're a Vue developer, you'll feel right at home.

Roadmap ideas

  • More official backend layers
  • Rich ecosystem of feature layers
  • Better developer tooling and DX improvements
  • Community layers are very welcome! ❤️

License

MIT (planned)

Related Packages

create-pluto

CLI Wizard for creating a Pluto App

1,410
nuxt-cms-engine

CMS engine for nuxt framework

3,496 0
@shopware/cms-base-layer

Vue CMS Nuxt Layer for Shopware

91,927 230
create-easy-cms

Add Easy CMS to a Nuxt or Next.js project

14,568 2
@easy-cms/nuxt

Nuxt module for Easy CMS

13,929 2

Version History

Version Released License
0.17.0 MIT
0.16.4 MIT
0.16.3 MIT
0.16.2 MIT
0.16.1 MIT
Pre-releases (4)
Version Released License
0.0.1-alpha.4 MIT
0.0.1-alpha.3 MIT
0.0.1-alpha.2 MIT
0.0.1-alpha.1 MIT