nextjs-cms
v0.5.65
Published
A headless and comprehensive type-safe content management system built with Nextjs. This package provides all the core functionality for building dynamic CMS-powered websites with authentication, database integration, and extensible content sections.
Maintainers
Readme
nextjs-cms
A headless and comprehensive type-safe content management system built with Nextjs. This package provides all the core functionality for building dynamic CMS-powered websites with authentication, database integration, and extensible content sections.
Features
- Type-Safe API: Built with tRPC for end-to-end type safety
- Authentication System: JWT-based authentication with React hooks
- Database Integration: Drizzle ORM with MySQL support
- Extensible Content Sections: Modular section system with custom fields
- File Management: Built-in file upload and management capabilities
- Internationalization: Multi-language support with i18next
- Validation: Zod schema validation throughout
- Testing: Comprehensive unit and integration tests
Installation
Please install using the create-nextjs-cms package:
npx create-nextjs-cms
# or
yarn create nextjs-cms
# or
pnpm create nextjs-cms
# or
bun create nextjs-cmsQuick Start
1. Configure Your CMS
Create a cms.config.ts file in your project root:
import { CMSConfig } from 'nextjs-cms/core/config'
export default {
ui: {
title: 'My CMS Site',
defaultTheme: 'dark',
logo: '/logo.svg'
},
sections: {
path: './sections',
strict: false,
category: { allowRecursiveDelete: false }
},
media: {
upload: {
path: './public/uploads',
preserveExtension: true
}
}
} satisfies CMSConfig2. Create Content Sections
Create a section file in your sections folder. Sections are created using helper functions (simpleSection, hasItemsSection, or categorySection), and fields are created using field helper functions.
Simple Section Example
// sections/about.section.ts
import { richTextField } from 'nextjs-cms/core/fields'
import { simpleSection } from 'nextjs-cms/core/sections'
const about = richTextField({
name: 'about',
label: 'About',
required: true,
order: 1,
})
export default simpleSection({
name: 'about',
order: 1,
title: 'About Page',
db: {
table: 'about',
},
fields: [about],
})Has Items Section Example
// sections/blog.section.ts
import { textField, richTextField, dateField, photoField } from 'nextjs-cms/core/fields'
import { hasItemsSection } from 'nextjs-cms/core/sections'
const title = textField({
name: 'title',
label: 'Title',
required: true,
order: 1,
})
const content = richTextField({
name: 'content',
label: 'Content',
required: true,
order: 2,
})
const publishDate = dateField({
name: 'publish_date',
label: 'Publish Date',
required: false,
order: 3,
})
const coverPhoto = photoField({
name: 'coverphoto',
label: 'Cover Photo',
required: false,
order: 4,
})
export default hasItemsSection({
name: 'blog',
order: 1,
headingField: title,
title: {
section: 'Blog',
singular: 'Post',
plural: 'Posts',
},
db: {
table: 'blog',
},
fields: [title, content, publishDate, coverPhoto],
})Category Section Example
// sections/categories.section.ts
import { textField, photoField } from 'nextjs-cms/core/fields'
import { categorySection } from 'nextjs-cms/core/sections'
const title = textField({
name: 'title',
label: 'Title',
required: true,
order: 1,
})
const image = photoField({
name: 'image',
label: 'Image',
required: false,
order: 2,
})
export default categorySection({
name: 'categories',
order: 1,
headingField: title,
title: {
section: 'Categories',
singular: 'Category',
plural: 'Categories',
},
db: {
table: 'categories',
},
fields: [title, image],
depth: 2, // Allow nested categories
})API Reference
Core Modules
API (nextjs-cms/api)
- appRouter: Main tRPC router with all CMS endpoints
- createCaller: Server-side API caller factory
- createTRPCContext: Context factory for tRPC requests
Authentication (nextjs-cms/auth)
- JWT Management: Token creation, verification, and refresh
- React Hooks:
useAxiosPrivate,useRefreshToken - Server Actions: Authentication utilities for server components
Core (nextjs-cms/core)
- Config: CMS configuration management (
CMSConfig) - Fields: Content field helper functions (
textField,richTextField,dateField,photoField, etc.) - Sections: Section helper functions (
simpleSection,hasItemsSection,categorySection) - Submit: Form submission handlers (
SimpleSectionSubmit) - Factories: Section factory for loading sections (
SectionFactory)
Database (nextjs-cms/db)
- Client: Database connection and query utilities
- Schema: Database schema definitions
- Migrations: Drizzle migration helpers
Validators (nextjs-cms/validators)
Zod validators for all field types:
- Text fields, numbers, dates
- File uploads (images, documents, videos)
- Rich text content
- Select fields and checkboxes
Translations (nextjs-cms/translations)
- Multi-language support
- Dictionary management
- i18next integration
Field Types
The CMS supports various field types out of the box. Each field is created using a helper function that accepts a configuration object:
- Text:
textField({ name, label, required, order, ... })- Single-line text input - TextArea:
textAreaField({ name, label, required, order, ... })- Multi-line text input - RichText:
richTextField({ name, label, required, order, ... })- Rich text editor (TinyMCE) - Number:
numberField({ name, label, required, order, ... })- Numeric input - Date:
dateField({ name, label, required, order, ... })- Date picker - Select:
selectField({ name, label, required, order, options, ... })- Dropdown selection - SelectMultiple:
selectMultipleField({ name, label, required, order, ... })- Multi-select field - Checkbox:
checkboxField({ name, label, required, order, ... })- Boolean checkbox - Photo:
photoField({ name, label, required, order, size, thumbnail, ... })- Image upload - Video:
videoField({ name, label, required, order, ... })- Video file upload - Document:
documentField({ name, label, required, order, type, ... })- Document file upload - Color:
colorField({ name, label, required, order, ... })- Color picker - Map:
mapField({ name, label, required, order, ... })- Location/map field - Tags:
tagsField({ name, label, required, order, ... })- Tag input field - Password:
passwordField({ name, label, required, order, ... })- Password input - FieldGroup:
fieldGroup({ title, order, fields })- Group multiple fields together
Field Configuration
All fields require at minimum:
name: string - Unique field identifier (used in database)label: string - Display label for the fieldrequired: boolean - Whether the field is requiredorder: number - Display order of the field
Additional options vary by field type. See the API documentation for each field type for complete configuration options.
Section Types
Simple Section
Basic content sections with a single record. Use simpleSection() for pages like "About", "Contact", or "Settings" that have only one instance.
Key characteristics:
- Single record (always has ID = 1)
- No listing/browse page
- Direct edit page
- Requires
titleproperty
Example use cases: About page, Privacy Policy, Site Settings
Has Items Section
Sections that can contain multiple items. Use hasItemsSection() for collections like blog posts, products, or articles.
Key characteristics:
- Multiple records
- Browse/listing page with pagination
- Individual item pages
- Requires
headingFieldandtitleobject withsection,singular, andpluralproperties - Optional
coverPhotoField,search, andgalleryconfiguration
Example use cases: Blog posts, Products, News articles, Events
Category Section
Sections organized by categories with hierarchical structure. Use categorySection() for nested category systems.
Key characteristics:
- Hierarchical structure (configurable depth)
- Parent-child relationships
- Requires
headingFieldandtitleobject - Optional
depthproperty (default: 1, no nesting) - Automatically adds
parent_idandlevelfields when depth > 1
Example use cases: Product categories, Content categories, Navigation menus
Contributing
Contributions are welcome! Please read our contributing guidelines and submit pull requests to the main repository.
License
MIT License - see LICENSE file for details.
