npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

glyph-cms

v4.5.0

Published

Lightweight serverless headless CMS for Next.js — Prisma & Drizzle supported

Downloads

645

Readme

🔮 Glyph CMS

The drop-in Next.js admin panel that builds itself.

npm MIT


You don't need another SaaS tool just to manage your content.

Glyph is a headless CMS that mounts directly into your Next.js app. You write Zod schemas to define your data. Glyph reads them and auto-generates a full admin dashboard and REST API.

No separate repositories. No third-party servers. No webhooks to configure.

Use cases:

  • Marketing teams that need to edit landing pages without bothering developers.
  • Custom e-commerce inventory dashboards without the Shopify tax.
  • Internal admin panels to manage SaaS users and feature flags.

Features:

  • Schema-driven: Zod is the single source of truth for your database validation, API routes, and UI forms.
  • Serverless by default: It lives in your app/ directory and deploys right alongside your Next.js code.
  • Audit logs: Know exactly who changed what database row at 3 AM.
  • Role-based access: Keep your marketing team out of your core app settings.

Quick Start

npm install glyph-cms@latest zod@^3.22.0

If you're using Prisma, make sure you have the required dependencies:

npm install @prisma/client@latest
npm install -D prisma@latest

Note: If you are deploying to a serverless environment (like Vercel) and using Neon/Supabase, you should also install @prisma/adapter-pg and pg as per official Prisma docs.

If you're using Drizzle ORM, install these instead:

npm install drizzle-orm@latest
npm install -D drizzle-kit@latest
npx glyph-cms init

This scaffolds everything you need in seconds:

  • schemas/index.ts — Define your content shape here using Zod. You can export all your models from this single file.
  • glyph.config.ts — Register your schemas, collections, and admin users.
  • app/api/cms/[...params]/route.ts — The generated REST API handler.
  • app/cms/[[...slug]]/page.tsx — The admin dashboard UI.

Add the Tailwind source to globals.css so the dashboard looks crisp:

@source "../../node_modules/glyph-cms/dist/**/*.{js,mjs}";

Set your admin credentials in .env, run npm run dev, and head to /cms.


How It Works: Zod to CMS Magic

Write normal Zod. Glyph figures out the rest. It automatically maps Zod types to intuitive UI inputs.

// schemas/index.ts
import { z } from "zod";

export const PostSchema = z.object({
  title: z.string().min(1).describe("Post Title"),
  body: z.string(),                          // Automatically becomes a rich Textarea
  coverImage: z.string().url().optional(),    // URL input
  published: z.boolean().default(false),      // Toggle switch
  category: z.enum(["tech", "design"]),       // Dropdown select
  tags: z.array(z.string()),                  // Add/remove list repeater
});

// You can export all your other schemas here too!
// export const CategorySchema = z.object({ ... })

Register it in your config, and you instantly have a fully functioning CMS for that table:

// glyph.config.ts
import { defineConfig } from "glyph-cms";
import { PostSchema } from "@/schemas";

export default defineConfig({
  schemas: { Post: PostSchema },
  users: [{ username: process.env.GLYPH_ADMIN_USERNAME!, password: process.env.GLYPH_ADMIN_PASSWORD!, role: "admin" }],
});

🔒 Roles, Permissions & Public APIs

By default, everything requires admin authentication. But you have granular control:

// Only needed when you want public reads or role restrictions:
collections: [
  // Anyone can read posts via the API, but only admins can create/edit.
  { name: "Post", public: true },
  
  // Only users with the "superadmin" role can even see the Settings page.
  { name: "Settings", allowedRoles: ["superadmin"] },
],

Why the REST API? The API routes (/api/cms/*) power the admin dashboard. However, if you set public: true on a collection, you can fetch data directly from your frontend or mobile app using standard GET /api/cms/post requests without needing to write custom queries!


🕵️‍♂️ Audit Logs

Need to know who broke the production homepage? Enable Audit Logs.

// glyph.config.ts
export default defineConfig({
  auditLog: true, // Enable the logger
  schemas: {
    GlyphLog: GlyphLogSchema,
  },
  collections: [
    // Make GlyphLog read-only by providing an empty array.
    // This prevents anyone from modifying logs in the dashboard.
    { name: "GlyphLog", allowedRoles: [] }
  ],
  // ...
});

When enabled, Glyph tracks every single create, update, and delete action. It stores the exact diff of what changed, who changed it, and when.

Required Database Table: You must create a table named GlyphLog in your database for audit logs to work.

For Prisma (schema.prisma):

model GlyphLog {
  id         String   @id @default(cuid())
  action     String   // "CREATE", "UPDATE", "DELETE"
  collection String   // "Post", "User", etc.
  recordId   String   // The ID of the modified record
  diff       Json?    // The changes made
  user       String   // Username of the admin who made the change
  createdAt  DateTime @default(now())
}

For Drizzle (db/schema.ts):

import { pgTable, text, timestamp, jsonb } from "drizzle-orm/pg-core";

export const glyphLog = pgTable("glyph_log", {
  id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()),
  action: text("action").notNull(),
  collection: text("collection").notNull(),
  recordId: text("recordId").notNull(),
  diff: jsonb("diff"),
  user: text("user").notNull(),
  createdAt: timestamp("createdAt").defaultNow().notNull(),
});

Required Zod Schema (schemas/index.ts):

import { z } from "zod";

export const GlyphLogSchema = z.object({
  action: z.string(),
  collection: z.string(),
  recordId: z.string(),
  diff: z.any().optional(),
  user: z.string(),
});

⚡ CLI Magic: Generate Pages

Don't want to build the frontend pages yourself? Let Glyph scaffold Server Components for you:

# Generates a fully-typed React Server Component page that fetches from the API
npx glyph-cms generate --slug about

Note for Next.js 15 users: If you experience caching issues or errors with generated marketing pages, you may need to enable cacheComponents: true in your next.config.ts:

const nextConfig = {
  experimental: {
    cacheComponents: true, // required for "use cache" in Next 15
  }
};

Need to clean up?

npx glyph-cms remove --slug about

Using Drizzle ORM

Glyph supports Drizzle out of the box (PostgreSQL & SQLite only).

Step 1: Map your Drizzle tables in glyph.config.ts:

// glyph.config.ts
import { defineConfig } from "glyph-cms";
import { PostSchema } from "@/schemas";
import * as schema from "@/db/schema";

export default defineConfig({
  schemas: {
    Post: PostSchema,
  },

  // Drizzle only — map each collection to its Drizzle table object
  tables: {
    Post: schema.posts,
  },

  users: [{ username: process.env.GLYPH_ADMIN_USERNAME!, password: process.env.GLYPH_ADMIN_PASSWORD!, role: "admin" }],
});

Step 2: Wire it up in your API route:

// app/api/cms/[...params]/route.ts
import { createCmsHandler, createDrizzleAdapter } from "glyph-cms";
import { db } from "@/db";
import config from "@/glyph.config";

const handler = createCmsHandler(
  config,
  createDrizzleAdapter(db, config.tables!)
);

export { handler as GET, handler as POST, handler as PUT, handler as DELETE };

🛠 Recommended Workflow

For Prisma Users

  1. Update Database Schema: Add your tables in schema.prisma.
  2. Apply Migrations: Run npx prisma migrate dev --name "update" to sync the DB.
  3. Create Zod Schema: Add your schemas to schemas/index.ts.
  4. Update Config: Register the schema and collection in glyph.config.ts.
  5. Start Server: Run npm run dev and manage your content.

For Drizzle Users

  1. Update Database Schema: Add your tables in your Drizzle schema file (e.g. db/schema.ts).
  2. Apply Migrations: Run npx drizzle-kit push (or generate/migrate) to sync the DB.
  3. Create Zod Schema: Add your schemas to schemas/index.ts.
  4. Update Config: Add the schema and table to glyph.config.ts.
  5. Start Server: Run npm run dev and manage your content.

🚨 Troubleshooting & Common Errors

1. Prisma TableDoesNotExist or Invalid model.count() invocation

  • Why it happens: You added a model to schema.prisma but the actual database tables don't exist yet, or you ran prisma migrate reset which wiped the tables because no migration file existed for them.
  • Fix: Always run npx prisma migrate dev --name "add_models" after changing schema.prisma.

2. PrismaClient is unable to be run in the browser or Missing Client

  • Why it happens: The Prisma Client hasn't been generated after a schema update.
  • Fix: Run npx prisma generate.

3. Collection has no registered schema

  • Why it happens: You added a collection to collections: ["MyModel"] in glyph.config.ts but forgot to import and map its Zod schema.
  • Fix: Make sure it's mapped in the schemas object: schemas: { MyModel: MyModelSchema }.

4. Next.js Error: Only plain objects can be passed to Client Components

  • Why it happens: You are trying to pass the full config object (which contains Zod classes) from a Next.js Server Component to the <GlyphAdmin> Client Component.
  • Fix: Pass apiPath directly instead of the full config: <GlyphAdmin apiPath={config.apiPath || "/api/cms"} />

API

| Route | Method | Description | |---|---|---| | /:collection | GET | List (paginated, searchable) | | /:collection/:id | GET | Get one | | /:collection | POST | Create | | /:collection/:id | PUT | Update | | /:collection/:id | DELETE | Delete |

Query params: ?page=1&limit=20&search=hello&orderBy=createdAt&dir=desc


MIT © devberryy