nextjs-cms

Installation

Create a new nextjs-cms project, connect it to MySQL, and sign in to the admin panel.

Requirements

  • Node.js 20.9 or later (the minimum for Next.js 16).
  • MySQL 8 or MariaDB, running locally or reachable over the network. You need a user that can create and alter tables.
  • A package manager: pnpm (recommended), npm, yarn, or bun.

Quick start

Terminal
pnpm create nextjs-cms@latest my-cms

The installer copies the project, installs dependencies, and runs the setup wizard (database credentials and admin password). Then create the tables for your sections and start the app:

Terminal
cd my-cms
pnpm nextjs-cms --dev update-sections
pnpm dev

Open http://localhost:3000 and sign in with the username Master and the password you chose during setup.

What the installer asks

create-nextjs-cms
◆ What is your project named?            my-cms
◆ Add sample sections?                   ◻ Blog  ◻ Category  ◻ Settings
◆ What database provider?                MySQL
◆ Initialize a Git repository?           No
PromptWhat it does
Project nameFolder to create and the name in package.json. Pass it as the first argument to skip the prompt. Use . to install into the current (empty) folder.
Sample sectionsAdds ready-made files to sections/: a Blog (hasItemsSection with title, cover photo, rich text, tags and a gallery), Category (categorySection), and Settings (simpleSection). Press enter with nothing selected to start empty.
Database providerMySQL (including MariaDB). Other databases are not supported yet.
GitRuns git init and stages the files.

After copying the template, the installer:

  1. Installs dependencies with the package manager you ran it with.
  2. Generates random ACCESS_TOKEN_SECRET, REFRESH_TOKEN_SECRET, and CSRF_TOKEN_SECRET values in .env.
  3. Runs nextjs-cms --dev setup, which asks for your database credentials, creates the CMS system tables, and asks for a password for the Master admin.

Your sections' own tables are created by update-sections, which is why you run it once before the first pnpm dev, and again every time you change a section.

The setup command

If setup failed (for example, MySQL was not running) or you skipped it, run it yourself from the project folder:

Terminal
pnpm nextjs-cms --dev setup

It runs three steps in order:

  1. Database configuration: prompts for host, port, user, password and database name, tests the connection, and writes DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, and DB_NAME to .env.development (or .env.production without --dev).
  2. System tables: creates the CMS's own tables (admins, admin_privileges, access_tokens, editor_photos, logs, and bookkeeping tables) with drizzle-kit push.
  3. Master admin: asks for the password of the built-in Master account and grants it every permission.
Important:

If the system tables already exist, setup lists them and asks before dropping and recreating them. That deletes your admins and their permissions. Section tables (your content) are never touched by setup. To only reset the Master password, use set-master-admin instead.

If the database is already configured, skip step 1:

Terminal
pnpm nextjs-cms --dev setup --continue
Good to know:

The --dev (-d) flag goes before the command name and tells the CLI to read .env.development. Without it, the CLI reads .env. See the CLI reference for every command.

Environment variables

The generated .env and .env.development files contain everything the admin needs. You only edit these by hand when deploying or when a feature needs a key.

.env
# Auth: generated by create-nextjs-cms. Keep them secret and different per environment.
ACCESS_TOKEN_SECRET=...
REFRESH_TOKEN_SECRET=...
CSRF_TOKEN_SECRET=...
ACCESS_TOKEN_EXPIRATION=2h
REFRESH_TOKEN_EXPIRATION=1y

# Optional: needed by mapField (Google Maps)
NEXT_PUBLIC_GOOGLE_MAPS_API_KEY=

# Database: written to .env.development by `nextjs-cms -d setup` or `nextjs-cms -d db-config`
DB_HOST=localhost
DB_PORT=3306
DB_NAME=my_cms
DB_USER=root
DB_PASSWORD=...
VariableRequiredDescription
DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORDYesMySQL connection.
ACCESS_TOKEN_SECRETYesSigns short-lived access tokens (JWT).
REFRESH_TOKEN_SECRETYesSigns long-lived refresh tokens.
CSRF_TOKEN_SECRETYesSigns the CSRF token checked on every mutating request.
ACCESS_TOKEN_EXPIRATIONYesAccess token lifetime, in jsonwebtoken format (2h, 30m).
REFRESH_TOKEN_EXPIRATIONYesRefresh token lifetime (1y, 30d).
NEXT_PUBLIC_GOOGLE_MAPS_API_KEYFor mapFieldGoogle Maps JavaScript API key.

Next steps