Images, files and styles
Images and styles in Nuxt live in two places. The public/ folder is served to the browser as is, while files in app/assets/ are processed by the Vite bundler: it compresses them, adds a version tag to the name and checks that the file exists. The folder you choose decides how you refer to the file.
The public folder
Put an image into public/images/cover.jpg. The link to it starts from the site root, without the word public:
<!-- app/pages/index.vue -->
<template>
<section>
<img src="/images/cover.jpg" alt="Blog cover">
</section>
</template>The file also opens directly at http://localhost:3000/images/cover.jpg. This is the place for favicon.ico, robots.txt and files whose address must stay the same.
The app/assets folder
Put a logo into app/assets/images/logo.svg and refer to it through ~:
<!-- app/layouts/default.vue -->
<template>
<header>
<img src="~/assets/images/logo.svg" alt="My blog" width="40">
</header>
</template>Vite finds the file at build time and puts in an address like /_nuxt/logo.Bx3k9.svg. The tag in the name changes whenever the file changes, so the browser never shows a stale cached version. If the path has a typo, the build reports an error.
Which folder to choose
public/ | app/assets/ |
|---|---|
| The file is served as is | The file is processed by the bundler |
Link from the root: /images/cover.jpg | Link through ~/assets/... |
| The address stays the same | The address changes when the file changes |
Icons, robots.txt, downloadable files | Styles, fonts, interface images |
A global stylesheet
Create app/assets/css/main.css:
/* app/assets/css/main.css */
body {
margin: 0 auto;
max-width: 720px;
font-family: system-ui, sans-serif;
line-height: 1.6;
}And connect it to every page in nuxt.config.ts:
// nuxt.config.ts
export default defineNuxtConfig({
css: ['~/assets/css/main.css']
})After restarting npm run dev, all pages get the same font and width.
Component styles
Styles for one component go into its <style scoped> block:
<!-- app/components/PostCard.vue -->
<style scoped>
.post-card {
padding: 16px;
border: 1px solid #ddd;
border-radius: 8px;
}
</style>The word scoped limits the styles to this component: a .post-card class elsewhere on the site is not affected. For preprocessors like Sass, install the package (npm install -D sass) and set lang="scss" on the <style> block.
Common mistake
Writing src="/public/images/cover.jpg" or src="/assets/images/logo.svg". The word public is not part of the address, and files from app/assets/ are not available at a direct address. For public/ write the path from the root (/images/cover.jpg), for app/assets/ go through ~/assets/.