nextjs-cms

Workflow & Conventions

How to go from an idea to a merged pull request.

The loop

  1. Open or pick an issue. For public API changes, agree on the design in the issue first.

  2. Branch from main: fix/slug-uniqueness, feat/date-range-bounds, docs/hooks-examples.

  3. Write a failing test that captures the bug or the new behavior.

  4. Implement the change.

  5. Add a changeset if a published package changed:

    Terminal
    pnpm changeset

    Pick the packages, the bump (patch for fixes, minor for features, major for breaking changes), and write one or two sentences for the changelog, written for users of the package.

  6. Update the docs in apps/docs/content when behavior or options change.

  7. Run the checks locally:

    Terminal
    pnpm typecheck && pnpm lint && pnpm test:unit
  8. Open a pull request against main.

Changesets are required

The Changeset Check workflow runs pnpm changeset status --since origin/main on every pull request. A change to nextjs-cms, create-nextjs-cms, @nextjscms/translations, or a plugin without a changeset fails it. Changes that only touch apps/cms (ignored in .changeset/config.json), the docs, or tests don't need one; add an empty changeset (pnpm changeset --empty) if the check complains.

Code style

Prettier and ESLint enforce most of it:

  • 4-space indentation, 120-character lines.
  • Single quotes, no semicolons, trailing commas.
  • Imports sorted automatically; Tailwind classes sorted.

Beyond formatting:

  • Match the surrounding code. Comment density, naming, and patterns should look like the file you're in.
  • Validate at the edges. Field and section helpers validate their options with Zod strictObject so typos fail loudly at load time. Follow the same pattern for new options.
  • Server-only stays server-only. Modules that touch the database, the filesystem, or sharp must never be reachable from client components. Environment-neutral code (validators, conditional-rule evaluation, inline-image sizing) lives in leaf modules with type-only imports.
  • User-facing strings are translatable. Use getString(key, language) on the server and useI18n() in the admin, and add keys to the English base dictionary.
  • No silent failures. If a user's config can't work, throw with a message that names the section and field.

Commit messages

Short, imperative, and specific: Support 'now' as DateField default, Fix slug uniqueness check on locale submit. Explain the why in the body when it isn't obvious.

Pull request checklist

  • Tests cover the change (unit, and integration if SQL is involved).
  • pnpm typecheck, pnpm lint, and pnpm test:unit pass.
  • A changeset describes user-visible changes.
  • Developer docs are updated for new or changed options.
  • No edits to generated files (create-nextjs-cms/templates, dynamic-schemas, _section-hot-reload.js).