GitHub - SonicJs-Org/sonicjs: SonicJS - The edge-native headless CMS for Cloudflare Workers. Sub-100ms response times, zero cold starts, TypeScript-first. Built on D1, R2, and Hono.

8 min read Original article โ†—

GitHub stars npm downloads GitHub commit activity Discord TypeScript License: MIT

PR Tests codecov Tests npm version

The only headless CMS born on the edge. Zero cold starts. 15โ€“50ms API responses. 300+ global locations. TypeScript-first. 100% MIT open source โ€” every feature free, no Enterprise gate, ever.

sonicjs.com

๐Ÿ“ฆ Get Started

npx create-sonicjs@latest my-app

$0 to start ยท No signup required ยท Runs anywhere SQLite runs

Sponsor Open Collective

Deploy to Cloudflare

โš ๏ธ Note: This repository is for developing the SonicJS core package. To build an application with SonicJS, use the command above to create a new project.

๐Ÿณ Self-Hosting with Docker

No Cloudflare account? Run SonicJS on any server with Docker and SQLite:

docker build -t sonicjs .
docker run -d --name sonicjs -p 3000:3000 \
  -v $(pwd)/data:/app/data \
  -e JWT_SECRET=$(openssl rand -base64 32) \
  -e BETTER_AUTH_SECRET=$(openssl rand -base64 32) \
  sonicjs

# Create the first admin user
docker exec sonicjs npm run reset
# โ†’ admin@sonicjs.com / sonicjs! (change after first login)

See the Self-Hosting guide for Docker Compose, Node.js, backup strategy, and production hardening.

๐Ÿš€ Features

Edge Performance

  • โšก Zero Cold Starts: 0โ€“5ms cold start vs 500โ€“2000ms on Node.js CMSs
  • ๐ŸŒ Global by Default: 300+ edge locations โ€” not one region, one continent
  • ๐Ÿš€ Sub-50ms APIs: 15โ€“50ms API responses vs 1โ€“4s with relations elsewhere
  • ๐Ÿ“ˆ Auto-Scaling: Cloudflare handles traffic spikes โ€” no ops required

Developer Experience

  • ๐Ÿ”ง Schema-as-Code: Define your content model in TypeScript; SonicJS generates the REST API and admin UI
  • ๐Ÿ“ฆ create-sonicjs CLI: From schema to global API in minutes
  • ๐Ÿ”ฅ Hot Reload: Fast local development with Wrangler
  • ๐Ÿ“ฑ Modern Stack: Hono.js, TypeScript, D1, R2, HTMX

AI-Native Content Layer

  • ๐Ÿค– Native MCP Server: Auto-generated tools let Claude Code, Cursor, and VS Code read, create, and publish content
  • ๐Ÿ” RAG-Powered Search: Semantic search with natural-language queries โ€” zero extra infra
  • ๐Ÿ›  12 Specialized Claude Code Agents: Purpose-built agents for development (View all agents)

Content Management

  • ๐Ÿ“ Rich Text Editor: TinyMCE integration with customizable toolbars
  • ๐ŸŽ›๏ธ Dynamic Fields: Text, number, date, boolean, select, media, slug, and more
  • ๐Ÿ“š Content Versioning: Complete revision history with restore โ€” free, no paywall
  • โฐ Content Scheduling: Publish/unpublish automation with date controls
  • ๐Ÿ”„ Draft โ†’ Published Workflow: Role-based permissions throughout
  • ๐Ÿ’พ Auto-Save: Automatic content saving every 30 seconds
  • ๐Ÿ›ก๏ธ XSS Protection: Comprehensive input validation and HTML escaping

No Lock-In, No Paywalls

  • 100% MIT: Every feature in the core. No Growth tier. No Enterprise gate. Ever.
  • No VC Clock: No license rug-pull. No infra lock-in.
  • Runs Anywhere: Edge-native on Cloudflare Workers, or self-host on Docker/VPS โ€” anywhere SQLite runs.

๐Ÿ“Š How SonicJS Compares

SonicJS Strapi Payload
Edge-native โœ… Yes โŒ No โŒ No
Cold start 0โ€“5ms 500โ€“2000ms 500โ€“2000ms
API response 15โ€“50ms 1โ€“4s 1โ€“4s
Global locations 300+ 1 region 1 region
Version history Free Paywalled Paywalled
SSO / Audit logs Free $99+/mo $99+/mo
AI / MCP Included Upsold Upsold
License MIT (all features) MIT (limited) MIT (limited)

SonicJS is the only production-ready CMS built specifically for edge computing.

๐Ÿ›  Technology Stack

Core Framework

  • Hono.js - Ultrafast web framework for Cloudflare Workers
  • TypeScript - Strict type safety throughout
  • HTMX - Enhanced HTML for dynamic interfaces

Cloudflare Services

  • D1 - SQLite database at the edge
  • R2 - Object storage for media
  • Workers - Serverless compute runtime
  • KV - Key-value storage for caching
  • Images API - Image optimization and transformation

Development Tools

  • Vitest - Fast unit testing
  • Playwright - End-to-end testing
  • Wrangler - Local development and deployment
  • Drizzle ORM - Type-safe database queries

๐Ÿ Quick Start

For Application Developers (Using SonicJS)

# Create a new SonicJS application
npx create-sonicjs@latest my-app

cd my-app
npm run dev

# Visit http://localhost:8787

Your app includes:

  • โœ… SonicJS CMS pre-configured
  • โœ… Database migrations ready
  • โœ… Example content collections
  • โœ… Admin interface at /admin
  • โœ… Ready to deploy to Cloudflare

For Package Developers (Contributing to SonicJS)

# Clone this repository
git clone https://github.com/lane711/sonicjs.git
cd sonicjs

# Install dependencies
npm install

# Build the core package
npm run build:core

# Create a test app to validate changes
npx create-sonicjs@latest my-sonicjs-app

# Run tests
npm test

Setting Up a Fresh Database

# Create a fresh D1 database for your branch (run from project root)
npm run db:reset

This creates a new D1 database named sonicjs-worktree-<branch-name>, applies all migrations, and updates wrangler.toml.

Working with Database Migrations

Migrations live in packages/core/migrations/. Test apps reference them via npm workspace symlink.

From your test app directory (e.g., my-sonicjs-app/):

# Check migration status
wrangler d1 migrations list DB --local

# Apply pending migrations
wrangler d1 migrations apply DB --local

# Apply to production
wrangler d1 migrations apply DB --remote

Creating New Migrations:

SonicJS bundles migrations at build time (Workers can't access the filesystem at runtime).

  1. Create packages/core/migrations/NNN_description.sql (use CREATE TABLE IF NOT EXISTS and INSERT OR IGNORE for idempotency)
  2. Regenerate bundle: cd packages/core && npm run generate:migrations
  3. Rebuild: npm run build:core
  4. Apply locally: cd my-sonicjs-app && wrangler d1 migrations apply DB --local

Common Commands

npm run dev          # Start dev server
npm run deploy       # Deploy to Cloudflare
npm run db:migrate   # Apply migrations
npm run db:studio    # Open database studio
npm test             # Run tests

๐Ÿ“ Project Structure

sonicjs/
โ”œโ”€โ”€ packages/
โ”‚   โ”œโ”€โ”€ core/              # ๐Ÿ“ฆ Main CMS package (@sonicjs-cms/core)
โ”‚   โ”‚   โ”œโ”€โ”€ src/
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ routes/    # Route handlers (admin, API, auth)
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ templates/ # HTML templates & components
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ middleware/# Authentication & middleware
โ”‚   โ”‚   โ”‚   โ”œโ”€โ”€ utils/     # Utility functions
โ”‚   โ”‚   โ”‚   โ””โ”€โ”€ db/        # Database schemas & migrations
โ”‚   โ”‚   โ””โ”€โ”€ package.json
โ”‚   โ”œโ”€โ”€ templates/         # Template system package
โ”‚   โ””โ”€โ”€ scripts/           # Build scripts & generators
โ”‚
โ”œโ”€โ”€ my-sonicjs-app/        # ๐Ÿงช Test application (gitignored)
โ”‚                          # Created with: npx create-sonicjs@latest
โ”‚
โ”œโ”€โ”€ www/                   # ๐ŸŒ Marketing website
โ””โ”€โ”€ tests/e2e/             # End-to-end test suites

โš ๏ธ This is NOT an application repository โ€” it's for developing the @sonicjs-cms/core npm package.

๐Ÿ”ง Content Management

Creating Collections

Collections are TypeScript config objects registered at app startup โ€” no database table required.

// src/collections/blog-posts.collection.ts
import type { CollectionConfig } from '@sonicjs-cms/core'

export default {
  name: 'blog_post',
  displayName: 'Blog Post',
  slug: 'blog-posts',
  description: 'Article content collection',

  schema: {
    type: 'object',
    properties: {
      title: { type: 'string', title: 'Title', required: true, maxLength: 200 },
      content: { type: 'lexical', title: 'Content', required: true },
      publishedAt: { type: 'datetime', title: 'Published Date' },
    },
    required: ['title', 'content'],
  },

  managed: true,
  isActive: true,
} satisfies CollectionConfig
// src/index.ts โ€” register before createSonicJSApp
import { registerCollections, createSonicJSApp } from '@sonicjs-cms/core'
import blogPostsCollection from './collections/blog-posts.collection'

registerCollections([blogPostsCollection])
export default createSonicJSApp({ plugins: { register: [] } })

Field Types

  • string: Single-line text with validation
  • lexical: Rich text editor
  • number: Numeric input with min/max constraints
  • boolean: Checkbox with custom labels
  • datetime: Date/time picker
  • select: Dropdown with single/multi-select
  • slug: URL slug with auto-generation
  • user: User reference picker
  • media: File picker with preview

๐ŸŒ API Endpoints

Content Management

  • GET /admin/content/new?collection=id - Create new content form
  • GET /admin/content/:id/edit - Edit content form
  • POST /admin/content/ - Create content
  • PUT /admin/content/:id - Update content with versioning
  • DELETE /admin/content/:id - Delete content

Advanced Features

  • POST /admin/content/preview - Preview before publishing
  • POST /admin/content/duplicate - Duplicate content
  • GET /admin/content/:id/versions - Version history
  • POST /admin/content/:id/restore/:version - Restore version

Public API

  • GET /api/content - Get published content (paginated)
  • GET /api/collections/:collection/content - Get content by collection
  • GET /api/collections - List all collections

๐Ÿš€ Deployment

# 1. Update wrangler.toml with your project settings

# 2. Create production database
wrangler d1 create my-app-db

# 3. Apply migrations
npm run db:migrate:prod

# 4. Deploy
npm run deploy

Your app will be live at https://your-app.workers.dev.

Environment Configuration

# wrangler.toml
name = "my-sonicjs-app"
main = "src/index.ts"
compatibility_date = "2024-01-01"

[[d1_databases]]
binding = "DB"
database_name = "my-app-db"
database_id = "your-database-id"

[[r2_buckets]]
binding = "MEDIA_BUCKET"
bucket_name = "my-app-media"

๐Ÿงช Testing

npm test                # Unit tests
npm run test:watch      # Watch mode
npm run test:e2e        # E2E tests
npm run test:e2e:ui     # E2E with UI

๐Ÿ”Œ Plugin Development

// src/plugins/my-plugin/index.ts
import type { Plugin, PluginContext } from '@sonicjs-cms/core'

export default {
  name: 'my-plugin',
  version: '1.0.0',
  description: 'My custom plugin',

  async activate(context: PluginContext) {
    // Runs when the plugin is activated
  },

  async install(context: PluginContext) {
    // Runs once on install โ€” migrations, seed data, etc.
  },
} satisfies Plugin

๐Ÿ“š Documentation

โค๏ธ Sponsor

SonicJS is 100% open source and free forever. If you find it useful, consider sponsoring:

Sponsor on GitHub Support on Open Collective

100% of sponsorship funds go to marketing โ€” spreading the word about SonicJS to grow the community.

SonicJS is a member of Open Source Collective, a 501(c)(3) nonprofit. Donations are tax-deductible for US contributors.

Thank You to Our Sponsors

@mmcintosh @nickgraynews

๐Ÿ“ž Support


Built with โค๏ธ for the Cloudflare ecosystem ยท sonicjs.com