Docs
Next

Install in a Payload project

Add Systhema to an existing Payload and Next.js project, then generate its routes and artifacts.

On this page

Use this guide for an existing Payload App Router project. For a new site, the Payload template configures the adapters and scripts for you.

PrerequisitesLink to this section

  • Node.js 20.9 or newer and pnpm 10. The global CLI needs Node.js 22 or newer.
  • Registry access.
  • An existing Payload app with a working database adapter.
  • A clean branch and backups of any existing content.

StepsLink to this section

1. Install the packagesLink to this section

pnpm add @systhemaui/core @systhemaui/react @systhemaui/next @systhemaui/payload
pnpm add -D tailwindcss @tailwindcss/postcss postcss
pnpm add -D @payloadcms/next @payloadcms/plugin-nested-docs \
  @payloadcms/plugin-redirects @payloadcms/plugin-seo \
  @payloadcms/richtext-lexical @payloadcms/ui
pnpm add @payloadcms/plugin-import-export

Retain your existing payload, database adapter, graphql, sharp, Next.js and React dependencies. Keep all Payload packages on the same supported version. See Payload installation for the peer requirements and Lexical patch setup. Do not remove existing collections or frontend routes before reviewing how they will be integrated.

2. Add design inputs and configurationLink to this section

Place your exported tokens and manifest.json in src/tokens/. Use Figma export or Systhema Design.

For an existing app, generate only the core config first:

pnpm exec systhema-core init --ts --react --postcss

The --payload shortcut also creates Payload config and routes and cleans default files. Use it only when you have reviewed those writes. This procedure integrates your existing app explicitly instead.

systhema.config.ts
import type { SysthemaConfig } from '@systhemaui/core'
import manifest from './src/tokens/manifest.json'

const config: SysthemaConfig = {
  manifest,
  packages: { react: true, payload: true },
  optimization: process.env.NODE_ENV === 'production',
}

export default config

Import Systhema's Tailwind entry from your public stylesheet:

src/app/(site)/globals.css
@import '@systhemaui/core/tailwind';

This minimal config uses the default spacing rules. If you adopt the starter's fluid %screen% rule, retain its companion wide-screen overrides. See Responsive sizing and Production CSS optimization.

3. Wrap the Payload configLink to this section

The following complete example uses SQLite. Keep your existing adapter if it differs:

src/payload.config.ts
import { sqliteAdapter } from '@payloadcms/db-sqlite'
import { buildConfig } from 'payload'
import { withSysthema, type SysthemaPayloadPluginOptions } from '@systhemaui/payload'
import systhemaConfig from '../systhema.config'

const userSysthemaConfig: SysthemaPayloadPluginOptions = {
  locales: systhemaConfig.locales,
  livePreview: { mode: 'client' },
}

export default buildConfig(
  withSysthema(
    {
      secret: process.env.PAYLOAD_SECRET || '',
      db: sqliteAdapter({ client: { url: process.env.DATABASE_URI || '' } }),
    },
    userSysthemaConfig,
  ),
)

Set real PAYLOAD_SECRET, SYSTHEMA_API_SECRET, DATABASE_URI, NEXT_PUBLIC_SERVER_URL and APP_ENVIRONMENT values in your environment. Keep secrets out of version control. Do not replace the database adapter to move content; that requires a separate data migration.

withSysthema builds its own collections and globals. Move your existing custom definitions into customCollections and customGlobals, and review their access rules. Preserve existing storage, email and other plugins in the base config. Use withSysthema and Plugin options for the full contract.

Wrap your existing Next.js config as well:

next.config.ts
import type { NextConfig } from 'next'
import { withPayload } from '@payloadcms/next/withPayload'
import { withSysthema } from '@systhemaui/next/config'

const nextConfig: NextConfig = {}

export default withPayload(withSysthema(nextConfig), { devBundleServerPackages: false })

Merge your current Next.js settings into nextConfig. Keep the TypeScript @payload-config alias pointing at src/payload.config.ts.

4. Generate the public routesLink to this section

Review Project structure, then:

pnpm exec systhema-core payload create-app-files

This supplies the public shell, CMS catch-all, sitemap, gateway and missing Payload route group. Existing scaffold files are preserved. Review the generated files and resolve any collisions with your existing routes, especially the home page and /robots.txt.

Configure your branding and fonts in src/app/(site)/template.tsx. It uses Payload's RootLayout, RootHeader and RootFooter; retain its provider and consent wiring. Keep code-owned routes outside (systhema).

5. Add scripts and syncLink to this section

Merge these scripts into your existing package.json:

package.json scripts to merge
{
  "scripts": {
    "sync": "systhema-core sync && payload generate:types && payload generate:importmap",
    "generate:types": "payload generate:types",
    "generate:importmap": "payload generate:importmap"
  }
}
pnpm sync
pnpm exec tsc --noEmit

Before starting against existing data, follow Database migrations. Adding Systhema collections changes the schema.

Moving a customised robots.ts to the route handlerLink to this section

Older projects can have src/app/robots.ts instead of src/app/robots.txt/route.ts. The host-aware-robots codemod migrates an unchanged scaffold; it preserves a customized file for you to review.

  1. Create src/app/robots.txt/route.ts from the current Payload starter, for example from a separate project scaffolded with systhema create --template payload.
  2. Port your existing Allow and Disallow rules into its body array.
  3. Delete src/app/robots.ts after transferring those rules. Both files resolve to /robots.txt; do not keep both.

Retain export const dynamic = 'force-dynamic' and resolveSysthemaPublicOrigin(request) from @systhemaui/next/origin. The helper accepts only the configured public origin or locale domains; do not build a cached Sitemap directive from an unvalidated Host header. Keep the environment check that blocks indexing outside production.

The robots-host-allowlist codemod replaces the old header-derived origin in an unchanged route and reports a customized route for manual review. See Deploying for environment and caching behavior.

VerifyLink to this section

Start with your existing development script. Confirm /admin, create or select a homepage in General Settings, and verify the published page while signed out. Test unsaved live preview separately; custom blocks need client registration.

Use Forms, SEO, Localization and Cookie consent to configure those features. Follow Deploying before launch.