Quick Start
Docker Compose is the recommended way to run Foldergram.
It gives you the quickest path to a working install and includes the media tooling needed for video support and animated AVIF processing, so you do not need to set up Node.js, pnpm, or ffmpeg on the host first.
Preferred: Docker Compose
1. Create your local data layout
data/
gallery/
db/
thumbnails/
previews/2. Put media into folders under data/gallery
Foldergram does not index loose files placed directly in the gallery root.
data/
gallery/
trips/
oslo/
IMG_0001.jpg
clip-01.mp4
family/
summer-2024/
porch.webpThe important rule is simple:
- A non-hidden folder becomes an indexed album only when it directly contains supported media.
- Nested folders become separate albums if they directly contain media.
Optional: add folder stories and highlights with a reserved stories/ folder:
data/
gallery/
AnimalPlanet/
post-1.jpg
stories/
story-1.mp4
story-2.jpg
Lions/
clip-1.mp4
nested-1/
clip-2.jpgIn the default mode:
- direct media inside
AppFolder/storiespowers the folder avatar story - each direct child folder under
stories/becomes one highlight circle - nested folders stay inside that same highlight capsule
If you need folders literally named stories to behave like normal app folders, open Settings -> General Settings, enable Treat stories folders as normal app folders, then run a rescan from Settings -> Scan & Library.
3. Start the container
docker compose up -dThe included compose file:
- uses the GHCR image by default
- maps host port
4141by default - mounts
./data/gallery,./data/db,./data/thumbnails, and./data/previews - runs the app in production mode
- uses internal container paths under
/app/data - relies on the image's bundled
ffmpegandffprobe
Container startup also runs pending SQLite migrations automatically before the app opens the persistent database.
For the default Docker Compose setup, the container uses the image's built-in production defaults plus the mounted ./data/... volumes. The source-install .env file is not read directly inside the container.
The shipped Compose file sets IMAGE_DETAIL_SOURCE=preview and DERIVATIVE_MODE=eager.
If you want Docker to skip specific source folders from the start, also add GALLERY_EXCLUDED_FOLDERS in docker-compose.yml, for example:
GALLERY_EXCLUDED_FOLDERS: "@eaDir,thumbnails,Archive/cache"For an optional read-only public demo in Docker, add PUBLIC_DEMO_MODE="1" under the Compose environment: block. If the browser-visible origin differs from the upstream Node host, also set CSRF_TRUSTED_ORIGINS to that public origin.
If you cloned the repo and want to build locally instead, use:
docker compose -f docker-compose.yml -f docker-compose.local.yml up -d --build4. Open the app
http://localhost:4141for the apphttp://localhost:4141/api/healthfor a quick backend check
On first run, the server performs a startup scan because there is no existing index. Existing libraries keep using the current index on startup; run Scan Library from Settings whenever you want to refresh the library after changes.
On later upgrades, startup automatically applies pending SQLite migrations before the app reuses the existing database.
If you want the lowest upfront derivative work for a large library in Docker, edit docker-compose.yml before startup:
IMAGE_DETAIL_SOURCE=original
DERIVATIVE_MODE=lazyThat combination keeps image detail pages on originals and generates missing thumbnails or previews only when they are first requested.
If you plan to expose Foldergram on a homelab or LAN, open Settings after the first load and enable the admin password. From there, you can keep admin-only access, add a separate viewer password, or switch to public browse mode.
Inside Settings:
General Settingscontains stories mode, nested folder title format, excluded folders, Home/Reels defaults, and the default folder photo orderPlacescontains offline place-data preparation and place-assignment rebuilds for GPS-tagged photosScan & Librarycontains manual scan plus rebuild actions
If a scan finishes with skipped corrupt or unreadable supported media, the admin scan panel shows the full report path for that run. Foldergram writes those per-run reports under <DATA_ROOT>/scan-errors/ and marks the run completed_with_errors.
Until you enable password protection, Foldergram starts without an auth gate, so Settings and the library-maintenance controls are available immediately to whoever can reach the app.
Optional: run from source for development
Foldergram is a pnpm workspace monorepo with three workspaces:
serverclientdocs
Use the source workflow when you want to develop or modify the app itself.
Prerequisites
| Requirement | Notes |
|---|---|
| Node.js 22 | The repo is configured for Node 22. |
pnpm | Matches the workspace scripts and lockfile. |
| FFmpeg and FFprobe | Required on the host if you run the app outside Docker and want video support. |
Development startup
pnpm install
cp .env.example .env
pnpm devpnpm dev includes the same automatic migration step before the server opens the database.
This runs:
- the Vite client on
http://localhost:4141, with automatic fallback through4144 - the Express server on
http://localhost:4140 - the VitePress docs site on
http://localhost:4145, with automatic fallback to the next free port
Useful commands
docker compose up -d
docker compose down
pnpm migrate
pnpm rescan
pnpm test
pnpm build
pnpm start
pnpm build:docsWhat to expect after startup
- Feed, folder pages, likes, explore, and moments read from SQLite, not directly from disk.
- Thumbnails are generated under
data/thumbnails. - Previews are generated under
data/previews. - In the default unprotected state, Settings is available immediately.
- After access protection is enabled, only admin sessions can open Settings or run scan and rebuild actions. Viewer and public sessions stay browse-only.
If nothing appears, start with Troubleshooting.