FolderFrame

Ways to install

The packaged container is the simplest option. Docker Run and Docker Compose are alternatives—choose one, not both.

Before you start

  • Choose one or more dedicated directories containing only media you intend to expose.
  • Mount the primary library read-only at /media/Library; additional libraries use unique sibling paths such as /media/Archive. Leave /media itself unmounted.
  • Choose a persistent /config directory if settings, thumbnails, manifests and Photo Info metadata should survive container recreation.
  • The published image supports linux/amd64 and linux/arm64.
  • FolderFrame has no built-in authentication or TLS and listens on container port 8080.

Discovery modes. auto tries a published manifest before directory listings, directory uses live listings only, and manifest requires the generated index. Static hosts can use strict manifest discovery without fabricated directory pages. Static-host setup

OPTION 1

Docker Run

Use this when you prefer one command. Replace both source paths with absolute paths on your Docker host. The media directory must exist; the first command creates the persistent configuration directory. Host port 8088 maps to container port 8080.

SHELL
mkdir -p /absolute/path/to/folderframe-config

docker run -d \
  --name folderframe \
  --restart unless-stopped \
  -p 8088:8080 \
  -e FOLDERFRAME_THUMBNAILS=true \
  -e FOLDERFRAME_MANIFEST=true \
  -e FOLDERFRAME_THUMBNAIL_INTERVAL=3600 \
  --mount type=bind,source=/absolute/path/to/media,target=/media/Library,readonly \
  --mount type=bind,source=/absolute/path/to/folderframe-config,target=/config \
  ghcr.io/the-grog/folderframe-deployment:stable

Open http://SERVER-IP:8088/.

Configuration variables. Docker Run accepts supported FOLDERFRAME_* settings with -e NAME=value. Thumbnails and manifests are enabled by default, can be switched independently, and share FOLDERFRAME_THUMBNAIL_INTERVAL (3600 seconds by default). Blank variables defer to the persistent JSON configuration. Configuration quick reference

OPTION 2

Docker Compose

Use this instead of Docker Run when you want the configuration saved in a file. Replace both source paths with absolute existing directories for media and persistent configuration.

COMPOSE.YAML
services:
  folderframe:
    image: ghcr.io/the-grog/folderframe-deployment:stable
    container_name: folderframe
    restart: unless-stopped
    environment:
      FOLDERFRAME_THUMBNAILS: "true"
      FOLDERFRAME_MANIFEST: "true"
      FOLDERFRAME_THUMBNAIL_INTERVAL: "3600"
    ports:
      - "8088:8080"
    volumes:
      - type: bind
        source: /absolute/path/to/media
        target: /media/Library
        read_only: true
      - type: bind
        source: /absolute/path/to/folderframe-config
        target: /config

Save as compose.yaml, run docker compose up -d, then open http://SERVER-IP:8088/.

Configuration variables. Compose accepts supported FOLDERFRAME_* settings through .env or an environment: block. Thumbnails and manifests are enabled by default, can be switched independently, and share FOLDERFRAME_THUMBNAIL_INTERVAL (3600 seconds by default). Blank variables defer to the persistent JSON configuration. Configuration quick reference

Unraid

Find FolderFrame in Unraid Community Apps, install it, then choose a dedicated Media Folder and an unused WebUI port. Keep Generate Thumbnails and Persistent Media Manifest enabled for large galleries.

  • Repository: ghcr.io/the-grog/folderframe-deployment:stable
  • Container port: 8080
  • Primary media path: /media/Library, read-only; added libraries use unique siblings below /media/
  • Generate Thumbnails: FOLDERFRAME_THUMBNAILS=true
  • Persistent Media Manifest: FOLDERFRAME_MANIFEST=true
  • Thumbnail Scan Interval: FOLDERFRAME_THUMBNAIL_INTERVAL=3600 seconds; shared by both features
  • Persistent appdata maps to /config; no database, privileged mode, host network, PUID or PGID is required
Unraid instructions ↗

Home Assistant

The dedicated Home Assistant app and card are still planned. FolderFrame is not currently a Home Assistant add-on.

Run the Docker image on a separate Docker host—or alongside Home Assistant Container when you manage that Docker host—then open or embed its HTTP address from your Home Assistant dashboard. Home Assistant OS does not provide a supported way to run arbitrary Docker containers directly.

Keep FolderFrame reachable only on a trusted network unless a separate access layer supplies authentication and HTTPS.

STATIC HOSTING

Cloudflare Pages with GitHub Actions

Use strict manifest discovery when your host cannot run Python or create directory listings. Keep generate_thumbnails.py in the repository root, then let GitHub prepare the files Cloudflare Pages publishes.

Add photosCommit and pushAction builds thumbnails and manifestCloudflare Pages deploysReload Library

Reload Library does not generate or deploy files. It cache-busts and retrieves the newest manifest already published. New media appears only after its files and manifest have been regenerated and deployed.

Recommended: commit generated files

This recipe writes thumbnails and manifests back to the repository with GitHub’s built-in token. Cloudflare Pages Git integration then deploys the follow-up commit—no Cloudflare credential is stored in FolderFrame.

Show complete GitHub Action
.GITHUB/WORKFLOWS/FOLDERFRAME-LIBRARY.YML
name: Build FolderFrame static library

on:
  workflow_dispatch:
  push:
    branches: [main]
    paths:
      - "photos/**"
      - "generate_thumbnails.py"
      - ".github/workflows/folderframe-library.yml"

permissions:
  contents: write

jobs:
  build-library:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: Install image support
        run: |
          python -m pip install Pillow
          python -m pip install pillow-heif || true

      - name: Generate thumbnails and manifest
        run: |
          python generate_thumbnails.py photos thumbnails \
            --manifest folderframe-data/library.json

      - name: Commit generated library
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git add -A -- thumbnails folderframe-data
          git diff --cached --quiet || git commit -m "Update FolderFrame static library"
          git push

Manifest only

Skip generated previews when originals are already suitable for the grid.

SHELL
python generate_thumbnails.py photos \
  --manifest folderframe-data/library.json \
  --manifest-only

Commit generated output

Simplest with Cloudflare Pages Git integration. Store thumbnails/ and folderframe-data/ in Git so each generated commit triggers deployment.

CI artifact only

Generate files during CI and place them in the deployment artifact without committing them. This requires a direct Pages deployment action and Cloudflare credentials stored only as encrypted GitHub Actions secrets.

EXPECTED PUBLISHED LAYOUT
FolderFrame/
├── index.html
├── app.js
├── folderframe.config.json
├── photos/
├── thumbnails/
└── folderframe-data/
    ├── library.json
    └── library.d/
        └── *.json

Keep deployment secrets out of the browser. Browser JavaScript cannot safely store GitHub or Cloudflare credentials. Never put API tokens or secrets in folderframe.config.json.

After installation

1. Open the WebUIVisit the host address and port you configured.
2. Check your mediaConfirm folders and files from the read-only media mount appear in the gallery.
3. Set up a displayUse Link Builder for a slideshow, embedded view or dedicated screen.
Full deployment documentation ↗How it works