@kyro-cms/core
v0.9.0
Published
Astro-native headless CMS with multi-database adapters, multi-protocol APIs, and multi-vendor support
Maintainers
Readme
Kyro CMS
Astro-Native Headless CMS with Multi-Database Adapters, Multi-Protocol APIs, and Multi-Vendor Support
Why Kyro?
Kyro is built for Astro from the ground up. Unlike other CMS solutions that bolt on Astro support, Kyro is architected to leverage Astro's islands architecture, server output modes, and performance-first approach.
Key Features
- Zero-Config Development - SQLite by default for instant setup, no external dependencies
- Multi-Database - SQLite (dev), PostgreSQL, MongoDB via unified adapter interface
- Multi-Protocol API - REST, GraphQL, tRPC, and WebSocket from a single config
- Multi-Vendor - Built-in tenant scoping and row-level access control
- E-Commerce Ready - Products, orders, customers, inventory, coupons out of the box
- Plugin System - Extend with SEO, analytics, reviews, and more
- Any Styling - Tailwind, CSS Modules, Styled Components, or plain CSS
Quick Start
Option 1: Create New Project (Recommended)
npm create kyro@latestThis launches an interactive wizard that asks:
- Project name
- Database (SQLite, PostgreSQL, MongoDB)
- API protocols (REST, GraphQL, tRPC, WebSocket)
- Styling (Tailwind, CSS Modules, Styled Components, None)
- Authentication (JWT)
- Versioning/Drafts
- Admin dashboard
- Starting template (Minimal, Blog, E-commerce)
Option 2: Add to Existing Project
npm install @kyro-cms/core// kyro.config.ts
import { defineConfig, localAdapter } from "@kyro-cms/core";
export default defineConfig({
name: "my-app",
adapter: localAdapter({ path: "./data.db" }),
collections: {
posts: {
slug: "posts",
label: "Posts",
fields: [
{ name: "title", type: "text", required: true },
{ name: "slug", type: "text", required: true },
{ name: "content", type: "richtext" },
{ name: "published", type: "checkbox", defaultValue: false },
],
},
},
api: {
rest: true,
graphql: true,
},
});Database Adapters
SQLite (Default for Development)
import { localAdapter } from "@kyro-cms/core";
const adapter = localAdapter({
path: "./data.db", // or ':memory:' for in-memory
});Perfect for development and small projects. Zero configuration required - no external services needed.
PostgreSQL (Production)
import { drizzleAdapter } from "@kyro-cms/core";
const adapter = drizzleAdapter({
connectionString: process.env.DATABASE_URL,
});MongoDB (Flexible Schemas)
import { mongoAdapter } from "@kyro-cms/core";
const adapter = mongoAdapter({
connectionString: process.env.MONGODB_URI,
});API Protocols
Kyro exposes your data through multiple protocols simultaneously.
REST API
# List documents
GET /api/posts
# Get single document
GET /api/posts/:id
# Create document
POST /api/posts
{ "title": "Hello World" }
# Update document
PATCH /api/posts/:id
{ "title": "Updated Title" }
# Delete document
DELETE /api/posts/:idGraphQL
query {
postsFind(where: {}, page: 1, limit: 10) {
docs {
id
title
slug
}
totalDocs
}
}
mutation {
postsCreate(data: { title: "New Post", slug: "new-post" }) {
doc {
id
title
}
}
}tRPC
const client = createTRPCClient({
router: kyro.router,
transformer: superjson,
});
// Type-safe queries
const posts = await client.posts.find.query({ page: 1 });
const newPost = await client.posts.create.mutate({
title: "Hello",
slug: "hello",
});Core Export Splitting (Astro Support)
To support Astro's islands architecture and prevent Node.js-only dependencies (like Redis, bcrypt, or database drivers) from crashing your browser bundle, Kyro Core provides two distinct entrypoints:
1. @kyro-cms/core (Server-Only)
Use this for backend logic, API routes, database configuration, and authentication adapters. This entrypoint includes all Node.js built-ins.
import { createKyro, drizzleAdapter, RedisAuthAdapter } from "@kyro-cms/core";2. @kyro-cms/core/client (Browser-Safe)
Use this for Astro components, React/Vue/Svelte islands, styling, and types. This entrypoint is guaranteed to be free of Node.js dependencies.
import type { KyroConfig, CollectionConfig } from "@kyro-cms/core/client";
import { defaultLightTheme, generateCSSVariables } from "@kyro-cms/core/client";WebSocket (Real-time)
const ws = new WebSocket("ws://localhost:4321/api/ws");
ws.send(
JSON.stringify({
type: "subscribe",
collection: "posts",
event: "create",
}),
);
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
// Handle real-time updates
};Field Types
Kyro supports 21 field types:
| Type | Description |
| -------------- | -------------------------- |
| text | Single-line text input |
| textarea | Multi-line text |
| richtext | Rich text editor content |
| markdown | Markdown content |
| number | Numeric values |
| email | Email with validation |
| password | Hashed password storage |
| checkbox | Boolean toggle |
| date | Date/time picker |
| select | Dropdown selection |
| radio | Radio button group |
| color | Color picker |
| json | JSON data |
| code | Code editor content |
| array | Repeatable field groups |
| group | Nested field groups |
| relationship | Link to other documents |
| upload | File/media uploads |
| blocks | Structured content blocks |
| row | Horizontal field layout |
| collapsible | Collapsible field sections |
| tabs | Tabbed interface |
Example: Complex Fields
fields: [
{ name: "title", type: "text", required: true },
{
name: "author",
type: "relationship",
relationTo: "users",
required: true,
},
{
name: "tags",
type: "array",
fields: [
{ name: "name", type: "text" },
{ name: "slug", type: "text" },
],
},
{
name: "metadata",
type: "group",
fields: [
{ name: "views", type: "number", defaultValue: 0 },
{ name: "featured", type: "checkbox" },
],
},
];E-Commerce Collections
Pre-built collections for building online stores:
import { ecommerceCollections } from "@kyro-cms/core";
const kyro = createKyro({
adapter: localAdapter({ path: "./store.db" }),
collections: ecommerceCollections,
});
// Includes:
// - products (with variants, pricing, inventory)
// - categories (hierarchical)
// - customers (with addresses)
// - orders (with items, status tracking)
// - coupons (percentage, fixed, free shipping)
// - store settings (globals)Authentication
Built-in JWT authentication with multiple storage options:
import { RedisAuthAdapter, SQLiteAuthAdapter } from "@kyro-cms/core";
import { createAuthConfig } from "@kyro-cms/core";
// Use SQLite for development (zero-config, default)
const adapter = new SQLiteAuthAdapter({ path: "./data.db" });
// Use Redis for sessions (recommended for production)
const redisAdapter = new RedisAuthAdapter({
url: process.env.REDIS_URL,
tls: process.env.REDIS_TLS === "true",
});
// Or use PostgreSQL for production
import { PostgresAuthAdapter, createDatabase } from "@kyro-cms/core";
const { db } = await createDatabase();
const pgAdapter = new PostgresAuthAdapter({ db });
// Or use env-based config with all features
const authConfig = await createAuthConfig();
const { redis, routes, passwordPolicy, lockout } = authConfig;Authentication Features
- JWT Tokens - 24h expiry with refresh token support
- Multiple Storage Options - SQLite (dev), Redis, PostgreSQL via unified adapter interface
- Password Policy - 12+ chars, complexity requirements, history check
- Account Lockout - 5 failed attempts → 15 minute lockout
- Rate Limiting - Per-IP and per-user limits
- Audit Logging - 30-day retention with action tracking
CLI Commands
# Create admin user (first-run bootstrap)
kyro auth bootstrap -e [email protected] -p "SecurePass123!" -r admin
# Database setup
kyro db migrate # Run migrations
kyro db push # Push schema to database
kyro db seed # Seed default roles
kyro db studio # Open Drizzle StudioRBAC Roles (Hierarchy)
super_admin (100) > admin (90) > editor (70) > author (50) > customer (30) > guest (10)Environment Variables
# Database
DATABASE_URL=postgresql://user:pass@host:5432/kyro_cms
DATABASE_SSL=false
# Redis (sessions/cache)
REDIS_URL=redis://localhost:6379
REDIS_TLS=false
# JWT
JWT_SECRET=your-32-char-secret
JWT_EXPIRES_IN=24h
# Auth Settings
LOCKOUT_MAX_ATTEMPTS=5
LOCKOUT_DURATION_MINUTES=15
PASSWORD_MIN_LENGTH=12
# Bootstrap (first-run admin)
[email protected]
KYRO_ADMIN_PASSWORD=SecurePass123!Version History & Drafts
Track document changes with built-in versioning:
import { createVersionManager } from "@kyro-cms/core";
const versions = createVersionManager(adapter, {
versioningEnabled: true,
maxVersionsPerDocument: 50,
});
// Create a new version
const version = await versions.createVersion({
collection: "posts",
documentId: "abc123",
data: { title: "Updated Post" },
status: "draft",
createdBy: "user123",
});
// Publish
await versions.publishVersion({
collection: "posts",
documentId: "abc123",
versionId: version.id,
publishedBy: "user123",
});Admin Dashboard
Kyro includes a full admin dashboard:
npm install @kyro-cms/admin @kyro-cms/coreThe admin uses local utilities for API calls, date formatting, and validation.
---
// admin/index.astro
import { Admin } from '@kyro-cms/admin';
import config from '../kyro.config';
---
<Admin client:load config={config} />Features:
- Collection browser with filtering and sorting
- Document editor with all field types
- Media library
- Global settings editor
- Dark mode support
Plugin System
Extend Kyro with plugins:
import {
KyroPlugin,
SEOPLugin,
AnalyticsPlugin,
CommentsPlugin,
ReviewsPlugin,
WishlistPlugin
} from '@kyro-cms/core';
const kyro = createKyro({
adapter: localAdapter(),
collections: [...],
plugins: [
new SEOPLugin({
sitemap: true,
robotsTxt: true,
}),
new AnalyticsPlugin({
providers: ['google', 'plausible'],
}),
new CommentsPlugin(),
new ReviewsPlugin(),
],
});Creating Plugins
import { KyroPlugin } from "@kyro-cms/core";
class MyPlugin extends KyroPlugin {
name = "my-plugin";
hooks = {
"collection.beforeCreate": async (args) => {
// Transform data before creation
return { ...args, data: { ...args.data, source: "my-plugin" } };
},
"document.afterSave": async (args) => {
// Send webhook, log analytics, etc.
await sendWebhook(args);
},
};
}Styling System
Kyro ships with a complete styling system:
import {
ecommerce2026Theme,
generateCSSVariables,
generateTailwindConfig,
} from "@kyro-cms/core/client";
// Generate CSS variables
const cssVars = generateCSSVariables(ecommerce2026Theme);
// Generate Tailwind config
const tailwindConfig = generateTailwindConfig(ecommerce2026Theme);
// Custom themes
import { createAdminStyling } from "@kyro-cms/core/client";
const myTheme = createAdminStyling({
primaryColor: "#6366f1",
borderRadius: "medium",
fontFamily: "Inter",
});Deployment
Quick Start with Docker
# Start PostgreSQL + Redis
docker compose up -d
# Push schema to database
npm run db:push
# Create admin user
kyro auth bootstrap -e [email protected] -p "SecurePass123!"
# Start development
npm run devEnvironment Variables Required
# Database (PostgreSQL)
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/kyro_cms
DATABASE_SSL=false
# Redis (sessions/cache) - supports Redis Cloud
REDIS_URL=redis://localhost:6379
REDIS_TLS=false
# JWT (required)
JWT_SECRET=change-me-in-production-min-32-charsVercel
vercel --prodEnvironment variables:
DATABASE_URL- PostgreSQL connection stringJWT_SECRET- JWT signing secret
Railway
railway upDocker
cd deployments/docker
docker-compose up -dSee deployments/ for complete configuration.
Project Structure
kyro-cms/
├── packages/
│ └── create-kyro/ # Project scaffolding CLI
├── src/
│ ├── index.ts # Main exports
│ ├── createKyro.ts # Factory function
│ ├── registry/ # Config registry & validation
│ ├── fields/ # 21 field type definitions
│ ├── database/ # Adapter implementations
│ │ ├── local/ # SQLite adapter
│ │ ├── drizzle/ # SQL adapters
│ │ └── mongodb/ # MongoDB adapter
│ ├── api/ # Multi-protocol gateway
│ │ ├── rest/ # Hono REST
│ │ ├── graphql/ # GraphQL schema
│ │ ├── trpc/ # tRPC router
│ │ └── ws/ # WebSocket server
│ ├── auth/ # JWT authentication
│ ├── versions/ # Version history
│ ├── plugins/ # Plugin system
│ ├── styling/ # Theming
│ └── cli/ # CLI tools
├── admin/ # Admin dashboard (Astro)
├── examples/ # Example configurations
├── docs/ # Documentation
└── deployments/ # Deployment configsCLI Commands
# Initialize a new project
npm create kyro@latest
# Generate TypeScript types
kyro generate
# Push schema to database
kyro push
# Open database studio
kyro studio
# Check system health
kyro healthDocumentation
Contributing
Contributions are welcome! Please read our contributing guide before submitting PRs.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing) - Open a Pull Request
License
MIT License - see LICENSE for details.
Acknowledgments
Built with inspiration from:
- Payload CMS - The headless CMS that pushed the industry forward
- Strapi - Open source headless CMS
- Sanity - Real-time content infrastructure
