Getting started

Configuration

Configuration has three layers:

  1. Build-time environment variables decide what gets bundled (database driver, deployment target). Changing them requires a rebuild.
  2. Runtime environment variables: connection strings, secrets, storage credentials. Can change without rebuilding.
  3. Admin settings: site information, SEO / AI GEO, API cache rules. Stored in the database and effective immediately.

The complete variable list lives in .env.example at the repository root.

Required secrets

VariablePurpose
NUXT_JWT_SECRETsigns the login cookie (JWT), 32+ characters
NUXT_SETUP_TOKENinstall token. Recommended on public deployments: the setup wizard requires it to create the first admin, so nobody can claim the site first
NUXT_SESSION_PASSWORDrequired by the password hashing component, 32+ characters
NUXT_PUBLIC_SITE_URLpublic origin used for absolute links in sitemaps, hreflang tags and llms.txt

Database

VariableStagePurpose
NUXT_DB_DRIVERbuildsqlite (default) / pg / mysql; only that adapter is bundled
DATABASE_URLruntimefile:.data/cms.sqlite, postgres://user:pass@host:5432/db, mysql://user:pass@host:3306/db
DATABASE_POOL_MAXruntimepool size for pg / mysql, default 10
NUXT_DB_AUTO_MIGRATEruntime1 = apply pending migrations at startup (Node target)
NUXT_DB_TABLE_PREFIXbuildtable prefix, default cms_

On Cloudflare DATABASE_URL is ignored and the D1 binding DB is used; pg / mysql go through a Hyperdrive binding named HYPERDRIVE.

The three schemas live in server/database/dialects/<driver>/schema.ts with migrations in migrations, migrations-pg and migrations-mysql. Query code uses only the dialect-neutral Drizzle API; differences are absorbed by firstRow, insertReturning, updateReturning, upsert and likeCi exported from server/database/index.ts. Do not use .all(), .get(), .returning() or onConflictDoUpdate.

Languages

i18n/config.json:

{
  "fallbackLocale": "us",
  "defaultLocale": "zh",
  "locales": [
    { "code": "zh", "language": "zh-CN", "name": "简体中文", "file": "zh.json", "content": "zh" },
    { "code": "us", "language": "en-US", "name": "English", "file": "en.json", "content": "en", "aliases": ["en"] }
  ]
}
FieldPurpose
codeURL prefix and UI locale code, e.g. /us/...
languageBCP 47 tag used for hreflang, og:locale and JSON-LD
fileUI message file in i18n/locales/; several locales may share one
contentlocale code stored on content rows (posts.locale); defaults to code
aliasesother URL prefixes that 301-redirect to code, e.g. /en/** → /us/**

English content is always stored as en in the database while URLs use /us; /en redirects automatically. Legacy sites may keep cn as their Chinese code.

Language suggestion (off by default; NUXT_PUBLIC_LOCALE_SUGGEST=true or app.config nuxtcms.localeSuggest: true): when the visitor's browser languages (else the country Cloudflare reports) match another language of the site, a small bar in that language offers to switch; dismissing it is remembered. It never redirects, so search engines still see every language through hreflang. Endpoint: GET /api/locale-hint.

UI strings are stored in the translations table and editable under Admin → Translations; they override the message files. Initial values are seeded from the files on first start.

API conventions

Only GET and POST are used. Updates and deletes go through POST /api/admin/<resource>/:id with _method: 'put' | 'delete' in the body.

API cache

Admin /admin/cache:

  • enable switch and TTL (1-168 hours)
  • Cached API paths: empty means /api/public/**; paths must be under /api/, and /api/admin|auth|setup|docs|media are never cached
  • Excluded paths take precedence

Rule modes: exact, prefix, wildcard (* ?), contains, regex. NUXT_PUBLIC_API_CACHE_ENABLED, _MAX_AGE, _INCLUDE and _EXCLUDE provide initial values. Admin writes to posts, products, categories, settings and translations invalidate the cache automatically.

Media storage

VariablePurpose
NUXT_STORAGE_DRIVERlocal (default) / r2 / oss / cos / s3; empty on Cloudflare means the R2 binding BUCKET
NUXT_STORAGE_BUCKETbucket name
NUXT_STORAGE_REGIONe.g. oss-cn-hangzhou, ap-guangzhou, us-east-1
NUXT_STORAGE_ENDPOINToptional endpoint override (must address the bucket)
NUXT_STORAGE_ACCESS_KEY_ID / NUXT_STORAGE_SECRET_ACCESS_KEYcredentials
NUXT_STORAGE_ACCOUNT_IDneeded for R2 through the S3 API outside Cloudflare
NUXT_STORAGE_PUBLIC_URLCDN or bucket domain; when set, media URLs point there instead of the /api/media/<key> proxy

Alibaba Cloud OSS and Tencent Cloud COS are accessed through their S3-compatible APIs (SigV4).

SEO and AI GEO

Admin /admin/seo:

  • SEO tab: per-language site name, SEO title, meta description, keywords and share image; global Google / Bing / Baidu verification codes and extra robots rules.
  • AI GEO tab: per-language AI summary and audience, organization data (type, logo, official profiles), llms.txt switches and an allow / disallow policy for 16 AI crawlers.

Public endpoints: /robots.txt, /sitemap.xml (multilingual index with lastmod and an HTTP Last-Modified header), /__sitemap__/<lang>.xml, /llms.txt, /llms-full.txt, /api/public/ai-summary?locale=. Pages emit hreflang, x-default, og:locale and Organization / WebSite JSON-LD automatically.

AI search check (top of the AI GEO tab): llms.txt, AI search crawler access, structured data, hreflang, sitemap, title and description, HTTPS, canonical and response time of this site or any address, scored out of 100 with fixes. The logic is runAiAudit() in server/utils/ai-audit.ts (public use allows public addresses only) and <AiAuditReport :result> shows a result, so a site can offer a free public checker.

Deployment and split frontend / backend

VariableStagePurpose
NUXT_DEPLOY_TARGETbuildcloudflare-pages / cloudflare-worker / node / static-frontend
NUXT_PUBLIC_API_BASEbuild (frontend)backend URL for a static frontend
NUXT_CORS_ORIGINSruntime (backend)allowed frontend origins, comma separated
NUXT_HOST_REDIRECTSbuild/runtime (backend)whole-domain 301 redirects, source>target[>status] comma separated (source also matches www., * = every other domain), e.g. old.com>new.com,alias.fi>new.com; preserves path+query; works for Pages custom-domain aliases. Set at build time on CF. Admin → Redirects does the same without a deploy, see Redirects
NUXT_AUTH_COOKIE_SAME_SITEruntime (backend)none for cross-origin frontends (HTTPS required)

See Deployment.

Miscellaneous

VariablePurpose
NUXT_API_DOCS_KEYaccess key protecting /api/docs (OpenAPI)
NUXT_ALTCHA_HMAC_KEYHMAC key for the login challenge
NUXT_CF_ACCOUNT_ID / NUXT_CF_API_TOKENCloudflare credentials used by the deploy scripts (usually kept in .cloudflare.env)