# Asset Handling

How to place static assets (images, icons, fonts, PDFs, stylesheets) inside an
FSD project. Assets follow the same placement rules as code: group by use
case, not by type, and keep them next to the code that uses them.

> **Caution:** A custom top-level `assets` segment that aggregates all static
> files is **not recommended**. It violates the FSD principles of high
> cohesion and locality of changes. Place assets where they are used.

## Decision Tree

1. **Used by exactly one slice?** Keep the asset inside that slice, usually
   in the `ui/` segment, or in `model/` if it is part of business logic.
2. **Reused across the app (icons, placeholder images)?** Move to
   `shared/ui/`.
3. **Global stylesheet, font, or app-level resource?** Place in the `app/`
   layer (`app/styles/`, `app/fonts/`).
4. **Served as-is by the bundler (favicon, robots.txt)?** Use the framework's
   `public/` folder. The `public/` folder is not part of FSD and does not
   conflict with FSD layers.

## Slice-specific Assets

When an asset belongs to one page, widget, or feature, keep it inside that
slice. The asset lives next to the component that renders it:

```text
pages/
  home/
    ui/
      hero-image.jpg          ← Used only by HomePage
      HomePage.tsx
    index.ts
```

If a slice uses many static images, group them in a subfolder of `ui/`:

```text
pages/
  home/
    ui/
      previews/
        cake.jpg
        pizza.jpg
        sushi.jpg
      HomePage.tsx
    index.ts
```

### Non-UI Assets

Some assets are not part of the UI but are coupled to business logic. For
example, a PDF template used to generate invoices. Place these in the
`model/` segment alongside the logic that consumes them, not in `ui/`:

```text
features/
  billing/
    model/
      invoice-template.pdf    ← Coupled to create-invoice.ts
      create-invoice.ts
    index.ts
```

The principle is locality of changes: if you delete the slice, every file it
owns goes with it. An asset that lives in business logic should sit next to
that logic.

## Shared Assets

When the same asset appears across multiple slices, move it to `shared/ui/`.
Place reusable images in a topical subfolder, or place a single asset next to
the shared component that uses it:

```text
shared/
  ui/
    placeholders/             ← Reused placeholder images
      cake.jpg
      pizza.jpg
    Dropdown.tsx
    chevron.svg               ← Used only by Dropdown, kept next to it
```

A single icon used by exactly one component in the UI kit stays next to that
component. A library of icons or images reused across many components goes
in a topical subfolder.

## Global Assets

Global stylesheets and fonts belong in the `app/` layer because they are
imported by the application entrypoint, not by individual slices:

```text
app/
  styles/
    reset.css
    global.css
  fonts/
    inter.woff2
  main.ts
```

Theme variables, CSS resets, and font registrations are app-wide concerns.
They bootstrap the application's visual layer the same way providers
bootstrap the runtime layer.

## Public Folder

Most bundlers expose a `public/` folder at the project root. Files here are
served as-is, without bundling or hashing.

- Vite, Next.js, Nuxt: `public/` at the project root.
- Astro: `public/` at the project root (path is fixed and cannot be changed).

`public/` is not part of FSD. It does not collide with FSD layers and does
not need to live under `src/`. Use it for files that must be served at fixed
URLs: favicon, `robots.txt`, `sitemap.xml`, OG images, and similar.

```text
public/
  favicon.ico
  robots.txt
  og-image.png
src/
  app/
  pages/
  shared/
```

Some projects keep a project-local `app/public/` folder when the bundler
allows assets to live alongside the entrypoint. Both layouts are valid.

## Summary Table

| Asset                                  | Location                                  |
| -------------------------------------- | ----------------------------------------- |
| Image used by one page/widget/feature  | Inside the slice's `ui/` segment          |
| PDF or template tied to business logic | Inside the slice's `model/` segment       |
| Icon reused across the app             | `shared/ui/` (topical subfolder if many)  |
| Icon used by exactly one shared kit UI | Next to that component in `shared/ui/`    |
| Global CSS reset, theme variables      | `app/styles/`                             |
| Web fonts                              | `app/fonts/`, `public/`, or `app/public/` |
| Favicon, robots.txt, sitemap           | `public/` (or `app/public/`)              |

## Anti-patterns

- **Do not create a top-level `assets/` segment** that holds all images,
  fonts, and icons. It breaks cohesion and forces consumers to import from a
  folder unrelated to the code they are working on.
- **Do not extract a slice-local asset to `shared/` "in case" it gets
  reused.** Move it only when actual reuse appears.
- **Do not place CSS modules in an `assets/` folder.** A component's
  stylesheet belongs next to that component in `ui/`.
- **Do not name an FSD segment `public`.** The framework's `public/` folder
  is reserved and lives outside `src/`.
- **Do not split assets and the components that use them.** A page that
  ships a hero image should keep that image in the page so removing the page
  removes the image.

## See Also

- `references/layer-structure.md`: segment rules and layer organization
- [Desegmentation](https://fsd.how/docs/guides/issues/desegmented/): why
  technical-role grouping (including a generic `assets/` segment) hurts
  cohesion
