Open-source project
damongolding/immich-kiosk avatar
damongolding/immich-kiosk

Immich Kiosk turns a photo server into a slideshow with a config file

Highly configurable slideshows for displaying Immich assets on browsers and devices.

1,727 stars95 forksGoAGPL-3.0

At a glance

What is it?
Immich Kiosk is a Go program that serves a browser slideshow of Immich assets from a YAML config, packaged as a distroless container, and it is not affiliated with the Immich project itself.
Who is it for?
Immich Kiosk is a good fit for a wall display, a lobby screen or a photo frame browser that should show an Immich library without the Immich interface, because its whole surface is a config file plus a container port. It is the wrong tool if you need editing, uploads or sharing, since it is a viewer, and it will not help if your Immich instance sits behind a network the display cannot reach.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A viewer for someone else's photo server, not an Immich feature

Immich Kiosk is described in one line as highly configurable slideshows for displaying Immich assets on browsers and devices. That is the whole product. It connects to an Immich instance, picks assets according to configuration, and serves a browser view that cycles through them.

The README is explicit about the boundary: this project is not affiliated with Immich. That matters more than a disclaimer usually does, because the two drift independently. A Kiosk release can ship without any corresponding Immich change, and an Immich upgrade can change the API a given Kiosk version talks to without a Kiosk release to match.

The intended audience is narrow and obvious. It is someone with a home lab or a small server who wants photographs on a wall or a screen and does not want the full Immich web interface, which is designed for browsing a library rather than for leaving on display. The topics list the scope honestly: golang, immich, immich-slideshow, immichkiosk, photos and slideshow.

Support is informal by design. Bugs go to GitHub issues, and chat happens in a dedicated channel on the Immich Discord server. The author also states that the project is hand-curated without any direct AI assistance, while CodeRabbit reviews code changes for feedback, bug catching and typos. That is a claim about process rather than about the code, but it does tell you what a maintainer of a single-person project is choosing to spend time on.

config.example.yaml, config.schema.json and a validated config

The repository layout explains the configuration story better than the README does. There is `config.example.yaml`, a `demo.config.yaml`, and a `config.schema.json`. The schema file is the significant one: it means the configuration has a machine-readable shape, which in turn is why a JSON Schema validator sits in the Go module list alongside `xeipuuv/gojsonschema`. Configuration can therefore be checked rather than guessed at, and an invalid key should fail visibly instead of silently disabling a setting.

The compose file shows the contract with the host filesystem. The container expects a config directory mounted at `/config`:

yaml
volumes:
  - ./config:/config

Two optional mounts sit commented out in the same block, `./custom.css:/custom.css` and `./offline-assets:/offline-assets`. Both tell you something. A custom stylesheet mount means the slideshow is not sealed against restyling, and an offline assets mount means the browser side can be made to work without fetching assets from a CDN, which is the difference between a display that works on an isolated network and one that shows nothing.

The rest of the configuration mechanism runs through Viper, with `pelletier/go-toml/v2` and `go.yaml.in/yaml/v3` in the dependency list, plus `mcuadros/go-defaults` for filling unset keys. Human-readable durations come from `dustin/go-humanize`, and localization runs through `nicksnyder/go-i18n/v2` with a `locales/` directory at the repository root.

docker compose up against ghcr.io/damongolding/immich-kiosk

The shipped compose file is short enough to read in full, and it is the most concrete thing in the repository:

yaml
services:
  immich-kiosk:
    image: ghcr.io/damongolding/immich-kiosk:latest
    container_name: immich-kiosk
    tty: true
    environment:
      LANG: "en_GB"
      TZ: "Europe/London"
    ports:
      - 3000:3000
    volumes:
      - ./config:/config
    restart: always
    healthcheck:
      test: ["CMD", "/kiosk", "--healthcheck"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 10s

Three details in there are worth more than the rest. The port mapping publishes 3000, so the browser on the display device connects to whatever host you run it on. `tty: true` is set even though the program serves HTTP, which suggests colored terminal output is part of the intended experience when you run it locally rather than in production. And the healthcheck is a real self-check: `/kiosk --healthcheck` is executed as a command every 30 seconds, with a 5 second timeout, 3 retries and a 10 second grace period at start. That is a deliberate design choice, since it means a broken instance is detectable by an orchestrator instead of only by a person noticing a frozen screen.

The environment block sets `LANG` and `TZ`, and the Dockerfile sets `TERM=xterm-256color`, `DEBUG_COLORS=true` and `COLORTERM=truecolor`, which is why `tty: true` is there.

A three-stage build ending in distroless nonroot

The Dockerfile is the clearest statement of what this program is. It has three stages.

The first builds the frontend from `node:26-alpine`, copying the repository into `/app`, installing the Go task runner globally and running `npm ci` before `task frontend`. The second stage is the Go builder on `golang:1.27.2-bookworm`, which downloads modules, runs `go tool templ generate`, and cross-compiles with the container disabled and version stamped into the binary:

bash
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -a -installsuffix cgo -ldflags "-X main.version=${VERSION} -X github.com/damongolding/immich-kiosk/internal/utils.runningInContainer=true -s -w" -o dist/kiosk .

Two things are visible in that line. The `runningInContainer` flag is compiled into the binary, so the program knows it is containerized rather than having to guess. The build is static, with `CGO_ENABLED=0`, which is what allows the final image to be distroless.

The final stage is `gcr.io/distroless/static-debian13:nonroot`, which contains no shell and no package manager. It copies in `demo.config.yaml` and the built binary, switches to the `nonroot` user, and sets the entrypoint to `/kiosk` with the working directory set to `/`. The frontend build output is copied in explicitly, CSS and JS directories separately, because templ generates Go code that embeds them.

That image also explains a detail in the compose file: the healthcheck runs `/kiosk --healthcheck`, a command in the image, rather than a curl against a port, which is the only way to healthcheck a distroless container that has no shell.

Version 0.x, weekly-ish tags, and an AGPL obligation

The licence is AGPL-3.0, and for a server-side web application that has real consequences for anyone thinking about modifying it and putting it in front of other people. It is a different situation from a permissive library: the network use clause is what makes self-hosted AGPL services worth thinking about carefully. Read `LICENSE` and take your own view rather than relying on this paragraph.

Versioning is still pre-1.0, which is the honest signal about API and config stability. v0.44.1 was tagged on 2026-09-25, v0.44.2 on 2026-10-05, and v0.45.0 on 2026-10-13. Two of the last three are patch-level, one is a minor bump, and the gaps are days to weeks, so the project moves quickly. The release workflow itself is automated: `.release-please-manifest.json` and `release-please-config.json` handle versioning and `CHANGELOG.md` is generated from conventional commits, which is a good sign for anyone tracking changes.

The last push was on 2026-10-13, the same day as the v0.45.0 tag, and the repository is not archived. The project is also packaged for awkward targets: `unraid.md` at the root and a `flake.nix` with a `flake.lock` for Nix users.

For developers, the tooling is visible too. `.air.toml` is a live-reload configuration for Go, `taskfile.yml` splits into `taskfile.docker.yml` and `taskfile.frontend.yml`, `.golangci.yml` handles linting, `mise.toml` pins tool versions, and `AGENTS.md` and `CONTRIBUTING.MD` describe the working conventions.

What Kiosk does not do, and what to compare it against

The wrong-tool cases are easy to state. Kiosk does not upload, tag, edit or share. It does not manage albums or people. It does not replace the Immich mobile apps, which remain where you add and organise photos. If your requirement is anything about managing a library rather than displaying one, you want Immich itself and Kiosk is a distraction.

The second limit is network reach. Kiosk is a browser slideshow, so the display device must be able to reach the Kiosk server, and the Kiosk server must be able to reach Immich. Both hops have to work. A kiosk on a guest Wi-Fi network cannot reach a server bound to a private interface, and fixing that is network work rather than configuration work. The README does not document any authentication layer for the kiosk page itself, so exposing port 3000 to the internet without something in front of it deserves a decision first.

The real alternative is not a competing slideshow tool. It is Immich's own web interface, possibly left open in full-screen browser mode on the display device. The difference in approach is the configuration surface. Immich's web interface is built for browsing and searching a library, and it has no equivalent of a YAML file describing album selection, transition timing or offline assets. Kiosk's argument is not that it renders better; it is that a display does not need browsing controls at all, and a config file is a better way to describe an unattended screen than a logged-in session is.

Editorial conclusion

Immich Kiosk is a good fit for a wall display, a lobby screen or a photo frame browser that should show an Immich library without the Immich interface, because its whole surface is a config file plus a container port. It is the wrong tool if you need editing, uploads or sharing, since it is a viewer, and it will not help if your Immich instance sits behind a network the display cannot reach. Before deploying, copy `config.example.yaml`, review `config.schema.json` against the keys you intend to set, and keep the API credentials scoped to read access, since the container talks to your photo server as an authenticated client on port 3000.

Frequently asked questions

Is Immich Kiosk affiliated with the Immich project?

No. The README states plainly that this project is not affiliated with Immich. It is an independent viewer that displays assets from an Immich server, and the two projects release independently.

How do I run Immich Kiosk?

The shipped docker-compose.yaml pulls `ghcr.io/damongolding/immich-kiosk:latest`, publishes port 3000, mounts a host directory at `/config`, sets `LANG` and `TZ`, restarts always, and healthchecks with `/kiosk --healthcheck` every 30 seconds.

Can I change the look of the Immich Kiosk slideshow?

The compose file includes a commented-out mount for `./custom.css:/custom.css`, so a host stylesheet can be supplied directly. Another commented mount, `./offline-assets:/offline-assets`, covers serving frontend assets without network access.

How is Immich Kiosk built and licensed?

The Dockerfile builds the frontend on node:26-alpine, compiles the Go binary with `CGO_ENABLED=0` on golang:1.27.2-bookworm after `go tool templ generate`, and ships it in a gcr.io/distroless/static-debian13:nonroot image as the nonroot user. The licence is AGPL-3.0.

Does Immich Kiosk let me edit or upload photos?

No. It is a slideshow viewer for assets held in an Immich server. Uploading, editing and library management stay in Immich and its mobile apps.

Official sources

  1. damongolding/immich-kiosk on GitHub
  2. License: AGPL-3.0
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/damongolding-immich-kiosk.svg)](https://hysenlabs.com/projects/damongolding-immich-kiosk)

Was this useful?