frappe_docker/docs/08-reference/07-how-assets-are-handled.md

2.5 KiB

title
How Assets are handled

Assets Reference

Problem

The sites directory contains both persistent data (site config, uploaded files, etc.) and build-time artifacts (sites/assets). Mounting the entire sites directory as a Docker volume causes assets to be persisted alongside config, which leads to:

  • Stale assets surviving image updates
  • Asset/manifest mismatches after rebuilds
  • Assets being tied to the volume lifecycle rather than the image lifecycle

Solution

Assets are moved out of the sites volume during the Docker build and replaced with a symlink. This means assets always come from the image layer, while the rest of sites remains persistent.

How it works

During the image build (Containerfile), the following is done:

RUN cp -r /home/frappe/frappe-bench/sites/assets /home/frappe/frappe-bench/assets && \
    rm -rf /home/frappe/frappe-bench/sites/assets && \
    ln -s /home/frappe/frappe-bench/assets /home/frappe/frappe-bench/sites/assets

This runs before the VOLUME declaration, so the symlink is baked into the image layer.

At runtime:

/home/frappe/frappe-bench/
├── assets/          ← image layer (ephemeral, always matches the image)
├── sites/
│   ├── assets -> /home/frappe/frappe-bench/assets   ← symlink
│   ├── common_site_config.json                       ← persisted in volume
│   └── <site>/                                       ← persisted in volume
└── logs/            ← persisted in volume

Volume behavior

Path Persistent Source
sites/ (except assets) Yes Named volume
sites/assets (symlink) Yes (symlink itself) Named volume (sites)
assets/ (symlink target) No Image layer
logs/ Yes Unnamed volume

The symlink itself is persisted in the volume, but it always points to assets/ which lives in the image layer and is discarded on container recreation.

Important: bench build at runtime

Running bench build inside a running container will write new assets and eventually cause a mismatch between assets.json and the actual assets, breaking the UI. This can be recovered by recreating the containers

Note: restarting the containers is not sufficient — they need to be recreated to discard the writable layer.