Skip to main content
Version: Canary

Assets and Files

There are two ways to add an asset to your Redwood app:

  1. co-locate it with the component using it and import it into the component as if it were code
  2. add it to the web/public directory and reference it relative to your site's root

Where possible, prefer the first strategy.

It lets Vite include the asset in the bundle when the file is small enough.

Co-locating and Importing Assets

Let's say you want to show your app's logo in your Header component. First, add your logo to the Header component's directory:

web/src/components/Header/
├── logo.png
├── Header.js
├── Header.stories.js
└── Header.test.js

Then, in the Header component, import your logo as if it were code:

web/src/components/Header/Header.js
import logo from './logo.png'

const Header = () => {
return (
<header>
{/* ... */}
<img src={logo} alt="Logo" />
</header>
)
}

export default Header

If you're curious how this works, see the Vite docs on static asset handling.

Adding to the web/public Directory

You can also add assets to the web/public directory, effectively adding static files to your app. During dev and build, Redwood copies web/public's contents into web/dist.

Changes to web/public don't hot-reload.

Again, because assets in this directory don't go through Vite, use this strategy sparingly, and mainly for assets like favicons, manifests, robots.txt, libraries incompatible with Vite, etc.

Example: Adding Your Logo and Favicon to web/public

Let's say that you've added your logo and favicon to web/public:

web/public/
├── img/
│ └── logo.png
└── favicon.png

When you run yarn rw dev and yarn rw build, Redwood copies web/public/img/logo.png to web/dist/img/logo.png and web/public/favicon.png to web/dist/favicon.png:

web/dist/
├── static/
│ ├── js/
│ └── css/
├── img/
│ └── logo.png
└── favicon.png

You can reference these files in your code without any special handling:

web/src/components/Header/Header.js
import { Head } from '@redwoodjs/web'

const Header = () => {
return (
<>
<Head>
<link rel="icon" type="image/png" href="favicon.png" />
</Head>
<img src="img/logo.png" alt="Logo" />
</>
)
}

export default Header

Styling SVGs: The special type of image

By default you can import and use SVG images like any other image asset.

web/src/components/Example.jsx
import svgIconSrc from '../mySvg.svg'

const Example = () => {
return (
<>
<img src={svgIconSrc} alt="Logo" />
</>
)
}

export default Example

Sometimes however, you might want more control over styling your SVGs - maybe you want to modify the stroke-width or fill color.

The easiest way to achieve this, is to make your SVGs a React component. Open up your SVG file, and drop in its contents into a component – for example:

web/src/components/icons/CarIcon.tsx
import type { SVGProps } from "react"

export const CarIcon = (props: SVGProps) => {
return (
// 👇 content of your SVG file
<svg
className="fill-blue-500" // 👈 you can use classes, like with tailwind
stroke={props.strokeColor} // or adjust properties directly
// ...

If you needed to convert a whole library of SVGs into stylable (or animatable!) components, one easy way would be to use the SVGR cli

Custom fonts

There are many different ways to peel this potato – it's all a search away – but if you're using the CSS @font-face rule, we have a quick tip for you:

  1. Place your fonts in the public folder, so it gets carried across
  2. In your CSS, use absolute paths - the public folder being your root - to point to the font file (same as the Vite docs), for example:
web/
├── src
├── App.tsx
├── entry.client.tsx
├── index.css
├── ...
├── public
│ ├── favicon.png
│ ├── fonts
│ │ └── RedwoodNeue.woff2
/* in e.g. index.css */
@font-face {
font-family: 'Redwood Neue';
/* 👇 it's a relative path */
src: url('/fonts/RedwoodNeue.woff2')
format('woff2');
font-weight: 300;
font-style: italic;
ascent-override: 97%;
}