Nuxt docs, chapter by chapter

Getting started I — installation, configuration, views, assets, styling

The first Getting Started chapters — creating a project, nuxt.config with environment overrides, runtimeConfig versus app.config, external config files, app.vue/pages/layouts, the public and assets directories, and every way to load styles.

These chapters look basic and are where interviewers test whether you have set up projects yourself rather than inherited them: which config file handles what, where an image goes so that it is hashed, how a global stylesheet is registered, how $production/$development overrides work.

Know — Installation

  • Create a project: npm create nuxt@latest <name> (also pnpm/yarn/bun create nuxt), then npm run dev -- -o to start the dev server on http://localhost:3000 and open the browser. The CLI offers templates and module selection.
  • Prerequisites: a current Node.js (the active LTS is recommended), an editor with the Vue (Official) extension, and a terminal. Nuxt DevTools are enabled by default in development.
  • The starter is app/app.vue plus nuxt.config.ts with a compatibilityDate; you add app/pages/ when you need routing.

Know — Configuration

  • nuxt.config.ts exports defineNuxtConfig({...}). Environment overrides: $production, $development, $test, and named environments under $env: { staging: {...} } selected with nuxt build --envName staging; they are merged over the base config.
  • Environment variables and private tokens go through runtimeConfig: keys defined there can be overridden at runtime by NUXT_-prefixed variables (NUXT_API_SECRET, NUXT_PUBLIC_API_BASE), public is exposed to the client, everything else is server-only. A .env file feeds them in development and at build.
  • App configuration lives in app.config.ts (defineAppConfig), is reactive and public, and is read with useAppConfig().
  • runtimeConfig vs app.config: runtime config for environment-specific and private values, overridable by env vars; app config for public, build-time-known, reactive values such as theme tokens, not overridable by env vars.
  • External configuration files: Nuxt ignores nitro.config.ts, vite.config.ts, webpack.config.ts and postcss.config.js; use the nitro, vite, webpack and postcss keys of nuxt.config instead. Other tools' files (.eslintrc, tailwind.config.js, vitest.config.ts, prettier.config.js) work as usual.
  • Vue configuration: vite.vue and vite.vueJsx for the Vite Vue plugins, webpack.loaders.vue for webpack, and the top-level vue key for compiler and runtime options (vue.compilerOptions, vue.propsDestructure, vue.runtimeCompiler).

Know — Views

  • app.vue is the entry component. Without a pages/ directory Nuxt does not include Vue Router; with pages, app.vue renders <NuxtPage />, optionally inside <NuxtLayout>.
  • Components in app/components/ are auto-imported by path-based name. Pages in app/pages/ map to routes; a page must have a single root element if page transitions are used. Layouts in app/layouts/ wrap pages with a <slot />; default.vue applies unless definePageMeta({ layout }) picks another.
  • Extending the HTML template: a Nitro plugin hooking render:html can modify the rendered document (html.head.push(...)), and app.head in nuxt.config sets defaults; there is no app.html template file to edit.

Know — Assets

  • public/ is served from the site root as-is, unprocessed: public/img/logo.png is /img/logo.png. Use it for robots.txt, favicons, files that must keep their names.
  • app/assets/ is processed by the bundler: referenced files get hashed names and are optimised; reference them as ~/assets/img/logo.png in templates and CSS.
  • Static vs dynamic src: the bundler can only rewrite paths it sees at build time, so a dynamic :src="'~/assets/' + name" does not resolve; use import.meta.glob or explicit imports, or put the files in public/.

Know — Styling

  • Local stylesheets: import in a component's <style> (@use "~/assets/scss/main.scss"), or register globally with the css property in nuxt.config (css: ['~/assets/css/main.css']). Fonts live in public/ or assets/ and are declared with @font-face. Stylesheets from npm go in css too (css: ['animate.css']).
  • External stylesheets are added with app.head.link or useHead({ link }), including dynamically; a Nitro plugin can modify the rendered head for all pages.
  • Preprocessors: install sass, less or stylus and use lang="scss"; share variables with vite.css.preprocessorOptions.scss.additionalData. Preprocessor workers are experimental (vite.css.preprocessorMaxWorkers).
  • SFC styling: class and style bindings, v-bind() in CSS for reactive values, <style scoped>, <style module> with $style.
  • PostCSS is configured under postcss.plugins in nuxt.config (autoprefixer, cssnano, …). Different layouts can load different styles. Third-party libraries and modules: UnoCSS, Tailwind CSS (via the Vite plugin for v4, or @nuxtjs/tailwindcss), and UI libraries as modules.

How it works

nuxt.config.ts
export default defineNuxtConfig({
  compatibilityDate: '2026-09-01',
  css: ['~/assets/css/main.css', 'animate.css'],
  app: {
    head: {
      link: [{ rel: 'stylesheet', href: 'https://fonts.example.com/inter.css' }],
    },
  },
  vite: {
    css: { preprocessorOptions: { scss: { additionalData: '@use "~/assets/scss/_tokens.scss" as *;' } } },
  },
  postcss: { plugins: { autoprefixer: {} } },
  runtimeConfig: {
    apiSecret: '', // NUXT_API_SECRET
    public: { apiBase: '/api' }, // NUXT_PUBLIC_API_BASE
  },
  $production: { routeRules: { '/**': { headers: { 'x-env': 'production' } } } },
  $env: { staging: { runtimeConfig: { public: { apiBase: 'https://staging.example.com/api' } } } },
})
app/app.vue
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>
app/components/Docs/Assets.vue
<script setup lang="ts">
// Dynamic asset paths must be resolved explicitly; the bundler cannot see string concatenation.
const icons = import.meta.glob('~/assets/icons/*.svg', { eager: true, import: 'default' }) as Record<string, string>
const icon = (name: string) => icons[`/assets/icons/${name}.svg`]
</script>

<template>
  <img src="~/assets/img/logo.png" alt="Logo"> <!-- processed: hashed URL -->
  <img src="/img/og.png" alt=""> <!-- public/: served as-is -->
  <img :src="icon('star')" alt="">
</template>
Gotcha· A vite.config.ts in a Nuxt project

Nuxt does not read it. Every Vite option goes under the vite key of nuxt.config.ts; the same is true for nitro.config.ts, webpack.config.ts and postcss.config.js. A stray vite.config.ts is a common reason "my alias does not work".

Verify before the interview:

The exact Node.js version requirement stated on the Installation page, and the current list of templates offered by npm create nuxt.

docs ↗

Exercise

Exercise
  • Create a project, add $production and $env.staging overrides that change runtimeConfig.public.apiBase, and print the value in app.vue under nuxt dev, nuxt build && node .output/server/index.mjs and nuxt build --envName staging.
  • Put the same image in public/ and app/assets/, reference both, and compare the URLs in the rendered HTML after a build.
  • Register a global stylesheet through css, add an npm stylesheet, and add a <link> with useHead in one page only; verify where each ends up in the HTML.

Be able to say

Be able to say· Where does configuration live in a Nuxt project?

"In nuxt.config.ts for the framework, the build and the modules, with $development, $production and named $env overrides. Environment-specific and private values go under runtimeConfig, which NUXT_-prefixed environment variables override at runtime, with a public half exposed to the client. Public, reactive, design-level values go in app.config.ts. Tool configuration for Vite, Nitro, webpack and PostCSS is nested inside nuxt.config under their own keys rather than in separate files, while ESLint, Tailwind, Prettier or Vitest keep their usual files."

Your notes

Open in Notes

Nothing yet. Notes filed here show up on this page and the section overview.