Nuxt Config
All CWA configuration lives under the cwa: key in nuxt.config.ts. The module merges your config with its defaults at build time.
Runtime Config
The API URLs are set via Nuxt's runtimeConfig so they can be overridden per-environment using environment variables:
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
public: {
cwa: {
apiUrl: 'http://api-internal', // server-side (SSR)
apiUrlBrowser: 'https://api.example.com' // client-side
}
}
}
})
In Docker Compose these typically differ — the server-side URL uses the internal Docker network hostname while the browser URL is the public domain.
Override at deploy time via environment variables:
NUXT_PUBLIC_CWA_API_URL=http://api:8080
NUXT_PUBLIC_CWA_API_URL_BROWSER=https://api.example.com
Either URL may point at a bare host (https://api.example.com, http://api:8000) or include a path prefix (https://example.com/_api) — both are supported.
https://api.example.com/ or https://example.com/_api/ is currently mishandled and will break resource resolution. Write the URL without it.Full cwa: Reference
export default defineNuxtConfig({
cwa: {
// Register your custom components for the admin "Add Component" dialog
resources: {
Title: {
name: 'Title Block',
description: 'A headline or section title',
instantAdd: false, // true = skip config dialog, add immediately
defaultData: { // pre-fill fields on creation
title: 'New Title'
}
// Note: component style options are NOT declared here — see below
}
},
// Register your layout components for the admin panel
layouts: {
Primary: {
name: 'Primary Layout',
// Style name → the classes it applies. A "Default" (no classes)
// option is added for you.
classes: {
'Light': 'bg-white text-gray-900',
'Dark': 'bg-gray-900 text-white'
}
}
},
// Register your page template components
pages: {
Primary: {
name: 'Primary Page',
classes: {
'Big Text': 'text-2xl'
}
},
BlogDetail: {
name: 'Blog Article'
}
},
// Register PageData types for the admin data management panel
pageData: {
BlogArticleData: {
name: 'Blog Articles',
// Human-readable labels for pageDataProperty position pickers.
// Falls back to auto-split camelCase → Title Case if omitted.
properties: {
htmlContent: 'Article Body',
heroImage: 'Hero Image',
},
metaFields: [
{
field: 'status',
type: 'select',
label: 'Status',
options: [
{ label: 'Draft', value: 'draft' },
{ label: 'Live', value: 'live' }
]
}
]
}
},
// How many levels deep to resolve nested page routes (default: 4)
pagesDepth: 2,
// Static defaults for site config — merged with API values, API wins on conflict
siteConfig: {
siteName: 'My App',
canonicalUrl: 'https://www.example.com',
fallbackTitle: true,
concatTitle: true,
indexable: true,
sitemapEnabled: true
},
// Resize large images in the browser before an admin upload sends them.
// These are the defaults. See "Image Uploads" below.
upload: {
image: {
enabled: true,
thresholdEdge: 2560,
thresholdPixels: 20_000_000,
maxEdge: 2560,
maxPixels: 20_000_000,
quality: 0.85
}
},
// Override the Nuxt layout applied to every page that doesn't set its own (default: 'cwa-root-layout')
layoutName: 'cwa-root-layout'
}
})
classes is a map, not a list. The key is the style name shown in the admin dropdown and the value is the class string it applies (a string[] is also accepted and joined). It exists on layouts and pages only — not on resources. Component style variants are declared in the Vue file via useCwaComponent(props, [], { styles: { classes } }); see Alternative UI Variants.type accepts 'input' (a text field) or 'select' (a dropdown). options is required for 'select' and ignored for 'input'.Config Key Reference
| Key | Type | Default | Description |
|---|---|---|---|
resources | Record<string, CwaResourceMeta> | built-in ComponentPosition and ComponentGroup entries | Your CMS component types and their admin metadata. Every component in app/cwa/components/ gets an entry automatically (name from the component name, plus its admin/ tabs and ui/ variants); your config is merged over it |
layouts | Record<string, CwaUiMeta> | {} | Your layout component types and admin display options |
pages | Record<string, CwaUiMeta> | {} | Your page template component types |
pageData | Record<string, { name?, properties?, metaFields? }> | {} | Your PageData resource classes for the admin data panel. properties maps PHP property names to human-readable labels used in position pickers; auto-splits camelCase if omitted. |
pagesDepth | number | 4 | Maximum nesting depth for nested page routes |
routeCacheLimit | number | 50 | Max routes kept in the instant-revisit cache. 0 disables eviction (unbounded — not recommended on large sites) |
staticRender | boolean | auto-detected | Set when the app serves prerendered/ISR/SWR HTML, so payload-hydrated resources are re-fetched on mount. Auto-detected from routeRules at build; set explicitly only to override |
pageCache | { enabled?, sharedMaxAge?, staleWhileRevalidate? } | { enabled: true, staleWhileRevalidate: 0 } | Shared-cache headers for rendered page HTML. sharedMaxAge is unset by default, so pages follow the API's s-maxage. See Page Caching |
upload.image | Partial<ImageDownscaleOptions> | { enabled: true, thresholdEdge: 2560, thresholdPixels: 20000000, maxEdge: 2560, maxPixels: 20000000, quality: 0.85 } | How admin uploads resize large images in the browser. See Image Uploads |
siteConfig | Partial<SiteConfigParams> | (defaults) | Static site config defaults merged with the API |
layoutName | string | 'cwa-root-layout' | Nuxt layout name used on CWA-managed content pages, and on any of your own pages that don't set a layout |
storeName | string | 'cwa' | Pinia store name prefix (rarely needs changing) |
Image Uploads
When an admin uploads a JPEG, PNG or WebP through useCwaResourceUpload, the browser resizes it first if it is large. By default, an image over 2560 px on its longest edge or over 20 megapixels is resized to fit both. cwa.upload.image changes this for the whole app. You only need to set the options you change:
// nuxt.config.ts
export default defineNuxtConfig({
cwa: {
upload: {
image: {
enabled: false // upload every image unchanged
}
}
}
})
A field can override these with its own imageDownscale option. The field's value wins, then this config, then the built-in default. The composable page explains each option and what resizing keeps.
maxEdge or maxPixels, check the API still accepts the result. See Large Images and PHP Memory.definePageMeta CWA Options
Pages in your app/pages/ directory can opt in or out of CWA behaviour using definePageMeta:
definePageMeta({
cwa: {
// Disable CWA route fetching on this page entirely.
// The page still mounts but CWA will not fetch a manifest or resolve any resources.
disabled: true,
// Render this layout component instead of the one resolved from the API's Layout
// resource. A registered component name (e.g. app/cwa/layouts/Primary.vue), rendered
// inside cwa-root-layout. It is not a Nuxt layout name.
staticLayout: 'CwaLayoutPrimary',
}
})
See Mixing Your Own Pages for the full pattern.