Foldergram turns a directory of photos into a self-hosted Instagram-style gallery
Self-hosted folder-based Instagram-style photo and video gallery app.
At a glance
- What is it?
- Foldergram indexes the media in a configured gallery root, stores metadata in SQLite, generates thumbnails and previews, and serves a progressive web app with a feed, reels, explore and profile pages. It is deliberately a local-only viewer, with no accounts, no uploads and no cloud sync, and the directory layout is the API.
- Who is it for?
- Adopt Foldergram when your photos already live in folders on a disk you control and you want a browsable, mobile friendly gallery with no account, no cloud and no upload pipeline. Do not adopt it if you need multi user accounts, comments, messaging, notifications or any remote API, since the README lists all of those as absent by design.
- 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 19 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A gallery whose content model is a directory
Foldergram is described as a local-only photo and video gallery for folders, with an Instagram-inspired browsing pattern, and the README's own summary is that it is a self-hosted web application that turns your local folders into a feed and profile, turning local folder to app folders, serving a fast progressive web app.
The mechanics are straightforward. Foldergram indexes supported media from a configured `GALLERY_ROOT`, stores metadata in SQLite, generates thumbnails and previews, and serves a fast feed-style web app for local browsing. Derivatives can be generated during scans or lazily on first request, and the image detail pages can be configured to use generated previews or the originals.
The feature list describes the app you get: Home, Reels, Explore, Library, Likes, Moments or Highlights, App Folder pages, post detail views, original-media download controls, delete actions, scan controls and rebuild tools. The Home feed has `Recent`, `Rediscover` and `Random` modes, and there is a dedicated `/reels` route with a video-only queue.
The stack is in the badges and the repository: Node.js 22 LTS, Vue 3, Express, ffmpeg, SQLite, Vite and a PWA, with TypeScript as the primary language and an AGPL 3.0 licence. The homepage is foldergram.github.io, the project publishes a GHCR image, and there is a live demo at foldergram.intentdeep.com. The releases are v1.2.2 from 2026-06-01, v1.2.1 from 2026-05-26 and v1.2.0 from 2026-05-19.
The folder rules decide everything
The How It Works section is a set of five rules, and they are the part of the README that decides whether your existing library will work as is.
An App Folder is any non-hidden folder under `GALLERY_ROOT` that directly contains supported media, and in reserved carousel mode a folder also qualifies when its `carousels/` directory has an immediate child containing supported media directly. Each supported image or video directly inside an App Folder becomes one indexed post, and media in `AppFolder/carousels/Post name/` is grouped into a carousel post in reserved mode.
Nested folders are not merged into their parent. A nested folder that directly contains supported media becomes its own App Folder with the parent folder name in the route, for example `/folder/parent-nested`. Files placed directly in `GALLERY_ROOT` are ignored, which is a sensible default and worth knowing before you wonder why a photo at the top level never appears.
The last rule is the escape hatch. A regular file named exactly `.nofoldergram` excludes its containing folder and all of its descendants, and a marker directly in `GALLERY_ROOT` is ignored. So a directory tree with mixed content, thumbnails, camera exports and vendor directories is manageable, and the marker is how you say not here.
Reads come from SQLite, and derivatives live in shards
Two implementation details decide how the app feels in use.
The first is that runtime reads come from SQLite and generated derivatives, not from live filesystem scans on every request. A scan is an expensive operation, and running it per request would make the app unusable on a large library. Instead the scan indexes the tree once, and the feed is served from the database.
The second is where derivatives are stored. Generated derivatives are now stored under stable asset-key shards instead of mirroring source folders. The upgrade path is described in the README: existing libraries stay readable during upgrade, then migrate in place on the next full scan, and during that upgrade Foldergram keeps stored paths pointed at files that already exist, repairs surviving legacy derivatives where possible, and lets later folder moves preserve the same indexed media identity and reuse existing thumbnails and previews.
The scan status also distinguishes discovery, derivative migration and derivative generation, so long-running maintenance work can report the right kind of progress for each phase. That matters for a first scan of a large library, which is the moment a user is most likely to think the application has hung.
Formats, and what ffmpeg is doing for you
The supported formats are listed plainly. Images are `.jpg`, `.jpeg`, `.png`, `.webp`, `.gif` and `.avif`. Videos are `.mp4`, `.mov`, `.m4v`, `.webm` and `.mkv`.
The behaviour notes are where the detail is. Animated image files keep their animation in the post viewer preview and the home feed cards, while folder and profile grids and other thumbnail surfaces remain static. Static AVIF files stay on the normal image pipeline, and animated AVIF image sequences generate static WebP thumbnails and animated WebP previews.
For source installs, video support and animated AVIF image-sequence processing require `ffmpeg` and `ffprobe`. The Docker image installs them inside the container, which is why the container route is the recommended one for most users.
The reason ffmpeg is needed at all is the video and the animated formats. A browser can display an MP4 that is already in a web friendly codec, and it can display an animated GIF or WebP, but it cannot make a thumbnail from a video or a still from an animated AVIF sequence. That work has to happen somewhere, and the project does it in the container rather than in the browser.
Installing with Docker in six steps
The recommended path uses the pre-built GitHub Container Registry image, and the README calls this the easy way for most users.
Create a folder and move into it:
mkdir foldergram
cd foldergramDownload the Compose file:
wget -O docker-compose.yml https://raw.githubusercontent.com/foldergram/foldergram/main/docker-compose.ymlCreate a first gallery folder with one album inside it:
mkdir -p data/gallery/example-albumMove a few photos or videos into `data/gallery/example-album/` so that there is something indexed to look at, and then start the container:
docker compose up -dContainer startup runs pending SQLite migrations automatically before the app opens the library database, so there is no separate migration step to remember. Then open `http://localhost:4141`.
In Docker, Foldergram runs in production mode and the app inside the container listens on `4141`, and the README notes that if you need a different host port you change the left side of the port mapping.
What the Compose file and the environment actually control
The shipped Compose file is the whole configuration surface for a Docker user:
services:
foldergram:
image: ghcr.io/foldergram/foldergram:latest
ports:
- "4141:4141"
environment:
IMAGE_DETAIL_SOURCE: preview
DERIVATIVE_MODE: eager
# Optional: skip specific source folders by name or by exact relative path.
# GALLERY_EXCLUDED_FOLDERS: "@eaDir,thumbnails,Archive/cache"
# Optional: enable read-only public demo behavior.
# PUBLIC_DEMO_MODE: "1"
# Optional when the browser-visible origin differs from the upstream Node host.
# CSRF_TRUSTED_ORIGINS: https://foldergram.example.com
volumes:
- ./data/gallery:/app/data/gallery
- ./data/db:/app/data/db
- ./data/thumbnails:/app/data/thumbnails
- ./data/previews:/app/data/previews
restart: unless-stoppedFour volumes are mounted, and the split is the important part. The gallery is your media, and it is mounted read write in the sense that the application indexes it, while the database, the thumbnails and the previews are separate directories so that generated files never end up inside your photo library.
The environment variables are the behavioural switches. `IMAGE_DETAIL_SOURCE` decides whether the detail page loads the generated preview or the original, with `preview` as the default, and `DERIVATIVE_MODE` decides whether derivatives are made during the scan or on first request, with `eager` as the default. `GALLERY_EXCLUDED_FOLDERS` takes a comma-separated list of folder names or exact relative paths, which is the programmatic version of the `.nofoldergram` marker. `PUBLIC_DEMO_MODE` turns on the read-only public browse behaviour, and `CSRF_TRUSTED_ORIGINS` is for the case where the browser-visible origin differs from the Node host.
The example environment file adds the rest, including `SERVER_PORT=4141`, the storage paths, `SCAN_MEDIA_ERROR_MODE` with `skip` as the default so that one unreadable file does not stop a scan, and the discovery and derivative concurrency settings, both at 4.
What Foldergram is not, and the alternative worth naming
The README has an explicit list of absences, and it is the most useful line in the document: no multi-user accounts, no cloud sync, no uploads, no comments, no messaging, no notifications and no remote APIs.
So this is a viewer with an optional access model, not a social network. There is optional role-based local access with admin, viewer and public browse modes, and shared likes are kept in SQLite for signed-in admin and viewer sessions, while public mode uses browser-local favorites instead. The difference is worth understanding: in public mode the likes live in the browser and follow the device, and there is no server-side record of them at all.
The alternative approach for the same job is a static gallery generator, which takes the same folder tree and produces a set of HTML files you can host on any static host. The difference in approach is where the media lives and who can use it. A static generator produces files and no database, no server and no access control, and it cannot offer a phone friendly progressive web app with offline support, a reels queue or a rebuild when the library changes. Foldergram keeps the library where it is, indexes it, and lets you browse it from a phone on your own network.
The one thing to check before committing is whether your library already matches the folder rules, because the mapping is strict about what directly contains what.
Editorial conclusion
Adopt Foldergram when your photos already live in folders on a disk you control and you want a browsable, mobile friendly gallery with no account, no cloud and no upload pipeline. Do not adopt it if you need multi user accounts, comments, messaging, notifications or any remote API, since the README lists all of those as absent by design. Verify first that your media is in the supported formats, that the machine can run `ffmpeg` and `ffprobe` if you install from source, that the folder layout you already have maps onto the App Folder rules, and that the version you pull matches the release you read, with v1.2.2 from 2026-06-01 the most recent tag and the last push on 2026-10-04.
Frequently asked questions
How do I install Foldergram?
The recommended path is Docker. Create a folder, download the Compose file with wget, create a first album with `mkdir -p data/gallery/example-album`, put some media in it, and run `docker compose up -d`, then open http://localhost:4141. Container startup runs the pending SQLite migrations automatically before the library database is opened.
How does Foldergram decide which folders to show?
Any non-hidden folder under `GALLERY_ROOT` that directly contains supported media becomes one indexed App Folder, and each supported image or video directly inside it becomes one post. Nested folders are not merged into their parent, files placed directly in `GALLERY_ROOT` are ignored, and a file named exactly `.nofoldergram` excludes its containing folder and all descendants.
Which media formats does Foldergram support?
Images as `.jpg`, `.jpeg`, `.png`, `.webp`, `.gif` and `.avif`, and videos as `.mp4`, `.mov`, `.m4v`, `.webm` and `.mkv`. For source installs, video support and animated AVIF image-sequence processing require `ffmpeg` and `ffprobe`, while the Docker image installs them inside the container.
Does Foldergram support multiple users, uploads or comments?
No. The README lists no multi-user accounts, no cloud sync, no uploads, no comments, no messaging, no notifications and no remote APIs. There is optional role-based local access with admin, viewer and public browse modes, and likes are shared in SQLite for signed-in sessions while public mode uses browser-local favorites.
Official sources
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.
[](https://hysenlabs.com/projects/foldergram-foldergram)Was this useful?