Customization
Your project has two applications and a set of layers they share. Before you change anything, decide which one owns it:
apps/siteis the public website: marketing pages, blog, docs, legal pages, contact form.apps/webis the signed-in product: account settings, administration, billing, APIs.packages/layer-*holds anything both applications use, or anything you'd want to copy into another Nuxt project.
Change a value in the application when it belongs to that application alone. Change it in a layer when both applications should follow. Technical details covers the ownership rule in full.
Colors
Nuxt UI reads its semantic colors from an application's app/app.config.ts. Neither application
ships one, so create the file in whichever application you want to change:
export default defineAppConfig({
ui: {
colors: {
primary: 'sky',
secondary: 'indigo',
neutral: 'slate',
},
},
})
packages/layer-base/app/app.config.ts already sets shared UI defaults, and the file you just
created merges over them — write only the keys you want to differ. The
Nuxt UI design system
lists every color and token you can set.
The brand color is separate
Two things render outside the browser and can't read Nuxt UI's theme: the fallback social image and the buttons in transactional email. Both read one constant:
export const BRAND_COLOR = '#00DC82'
Change it alongside your Nuxt UI colors, or your emails and social images drift away from your interface.
Name
Your product name lives in .env.project.schema at the root of the repository, because it names the
product and not the deployment — and because both applications read the same one:
PROJECT_DISPLAY_NAME=Acme
It reaches page titles, transactional email, and social images, arriving in each application as
NUXT_PUBLIC_APP_NAME.
It ships as REPLACE_ME, and nothing rejects that at build time. The deploy gate is what holds it,
and because it's read by both applications it holds every Runtime Context of both back rather than
one — so a deploy ships nothing until you have set it.
Project identity covers the rest of that file, and every name derived from it.
URLs and indexing
Each of these describes a deployment rather than the product, so they live in the value files rather than the schema:
| Key | Set in | What it does |
|---|---|---|
NUXT_PUBLIC_APP_BASE_URL | Both applications | The origin that application is served from |
NUXT_PUBLIC_APP_WEBSITE_BASE_URL | apps/web only | Points the product at the public website |
NUXT_PUBLIC_SITE_INDEXABLE | Both applications | Whether search engines may index it |
Environment values explains which file each one belongs in. First deploy is where you write the non-production origins, and Going to production is where you write production's.
Logo
Each application serves its own logo from its public/ directory:
apps/site/public/logo.png
apps/web/public/logo.png
Replacing those two files is the whole change. packages/layer-base defaults app.logo to
/logo.png, and the shared AppLogo component renders it.
To use a different file per color mode, set app.logo to an object instead, in that application's
app/app.config.ts — creating the file if you have not already:
export default defineAppConfig({
app: {
logo: {
light: '/logo-light.svg',
dark: '/logo-dark.svg',
},
},
})
AppLogo accepts either shape — a string renders one image, an object renders a color-mode pair —
so nothing else has to change. Put the files in that application's public/ directory.
apps/web can point
app.logo at an absolute URL on it instead of keeping a second copy.Favicon and page head
Replace apps/site/public/favicon.ico and apps/web/public/favicon.ico. Nuxt serves them without
any configuration, so there's nothing to declare unless you want a different filename or format.
The app.head block in an application's config is where the rest of the static head lives:
export default defineNuxtConfig({
app: {
head: {
title: ENV.NUXT_PUBLIC_APP_NAME,
htmlAttrs: {
lang: 'en',
},
},
},
})
Nuxt's SEO and meta guide covers the full API.
Fonts and design tokens
Each application owns a CSS entry point at app/assets/css/main.css, which imports a tailwind.css
beside it. Tailwind v4 theme tokens go in the second file:
@theme {
--font-sans: 'Inter', sans-serif;
--font-mono: 'JetBrains Mono', monospace;
}
The token defines the utility. Loading the font is a separate step — the browser needs the file before the utility means anything. Tailwind's theme documentation covers the other token groups.
Website settings
Values that belong to the public website, rather than to either application, live in the site layer's app config. The social links are there today:
export default defineAppConfig({
socials: {
x: 'https://x.com/your-handle',
},
})
The blog and docs layers each register their own content section from their own nuxt.config.ts,
under appConfig.contentSections. A new content section of your own follows that pattern in its own
layer.
Next steps
- Creating a page — add a page to either application
- Technical details — what each package owns
- Environment values — which file each value belongs in
