# Lychee: A Self-Hosted Photo Library in PHP and Vue

> LycheeOrg/Lychee is a self-hosted photo management system written in PHP with a Vue frontend. It installs fastest as a Docker Compose stack on port 8000, and version 7.0 changed the Docker image in ways that affect upgrades.

**LycheeOrg/Lychee** — A great looking and easy-to-use photo-management-system you can run on your server, to manage and share photos.

- Repository: https://github.com/LycheeOrg/Lychee
- Website: https://lycheeorg.dev
- Stars: 4,306 · Forks: 380
- Language: PHP
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/lycheeorg-lychee

## What Lychee Is For, and Who Should Run It

Lychee targets the person who wants their photo library on hardware they control. The README frames this directly: the project values "being in control of our own data, our own pictures." That is the pitch, and it defines the audience. You are the operator. You choose the server, you own the database, you decide who gets a link.

The repository is a Laravel application with a Vue and TypeScript frontend, which is visible in the layout: app/, routes/, config/ and database/ on the PHP side, resources/js/ on the client side, with vite.config.ts and tsconfig.json driving the frontend build. The package.json lists @nuxt/ui, Font Awesome, Leaflet with marker clustering and rotated markers, and a justified-layout package. Leaflet and marker clustering point at map and location views over your photos. The justified layout package explains the tiled album grid.

The project also ships a Supporter Edition with additional functionality, described on its own page at lycheeorg.dev/get-supporter-edition. The open source core stays MIT licensed. If you need a hosted photo service with no server to maintain, this is not that product, and no amount of configuration will make it one.

## How Lychee Is Put Together: Laravel, Vue, and a Worker

The Dockerfile shows a multi-stage build. Stage one runs composer install with --no-dev and strips markdown and test directories out of vendor/. Stage two runs npm ci and npm run build on a Node image. The comments in the Dockerfile name Laravel Octane with FrankenPHP as the runtime for the production stage. The repository also carries Dockerfile-legacy, and docker-compose.yaml notes that images tagged latest-legacy and edge-legacy use nginx as the base instead of FrankenPHP. Two runtimes, two image families, one application.

The README's quick-start note is the part worth reading closely: the minimal compose file "includes a separate worker container for background jobs." That is the architecture in one line. The web process serves requests, and a second process handles work that should not block a response. The compose file also supports a secrets convention: the comments state that every confidential value backing config/services.php supports setting a VAR_FILE variable to the path of a mounted file instead of the value itself, resolved by docker/scripts/01-validate-env.sh at container startup, before Lychee or PHP runs. That is a deliberate design choice, and it is the right one for third-party OAuth, AWS, mail and AI-vision credentials.

On the client side, the dependency list is unusually specific for a gallery. There is a WASM package for nested-set checking and another for zxcvbn password strength. There are Mollie and PayPal client libraries, which tells you payments are a first-class concern somewhere in the product, most likely around the Supporter Edition rather than the free core.

## Installing Lychee on Linux with Docker Compose

The README's fastest path is the minimal compose template. It downloads the file and starts the stack in detached mode:

```bash
curl -O https://raw.githubusercontent.com/LycheeOrg/Lychee/master/docker-compose.minimal.yaml
docker compose -f docker-compose.minimal.yaml up -d
```

The README states that after this you open http://localhost:8000 in your browser, and that this setup includes a separate worker container for background jobs. If the page loads, the web and worker processes are both up.

For a real deployment the README gives a fuller compose file with a MariaDB 11 service, health checks, named volumes, and a depends_on condition of service_healthy so the app waits for the database. The critical environment variables are APP_URL, DB_CONNECTION, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME and DB_PASSWORD. The README also shows how to generate the application key:

```bash
echo "base64:$(openssl rand -base64 32)"
```

Set the result as APP_KEY in the compose environment. The commented line in the README shows the expected form, base64: followed by the generated value. Skipping this step is the most common way a first run fails.

The README lists other installation routes: pre-built releases from GitHub Releases, or building from source, which requires PHP 8.4+, Composer and npm. The PHP badge in the README names PHP 8.4 and 8.5. If your distribution ships PHP 8.3, the source route will not work without adding a newer PHP repository.

## The Version 7.0 Docker Change Is the Upgrade Trap

The README carries a warning box titled "Upgrade Notice to Version 7.0." It states that version 7.0 introduces significant changes on the docker image and points to the upgrade guide in the documentation. This is the single most important operational fact about the project for anyone already running an older install. The image changed. The compose file you wrote for version 6 is not automatically the compose file you need for version 7.

The README does not document rollback. There is no stated procedure for returning to a previous version if an upgrade goes wrong, and no mention of database migration reversibility. Treat that silence as a constraint: before upgrading, take a database dump and a copy of the uploads directory, because the documentation does not promise you a way back.

The release cadence is worth noting for planning. Three releases are listed in the recent history, v7.8.3, v7.8.4 and v7.8.5, and the last push to the repository was on 2026-09-23. Patch releases arrive close together, sometimes on consecutive days. If you pin to latest, you are signing up for frequent image pulls. Pinning to a specific version tag is the calmer option, and the README's tag list confirms that latest maps to the last published version while edge maps to the last build on the master branch.

## Where Lychee Is the Wrong Tool

Lychee is a web application with a database behind it. That has consequences. If you want a folder of files on a NAS that any desktop photo app can open directly, Lychee adds a PHP runtime, a MariaDB instance, a worker process and a schema you must migrate. The files still live on disk under the uploads volume, but the application's view of them lives in the database. Losing the database without losing the files leaves you with a directory of images and no albums, no metadata and no share links.

The README's environment example also flags a sharp edge. REQUIRE_CONTENT_TYPE_ENABLED defaults to true, and the comment explains the requirement: API requests must send content-type: application/json or multipart/form-data depending on the type. The comment states this requirement prevents the use of the API from the API documentation page. So a default install has a stricter API than the docs page can satisfy, and you must set the variable to false to relax it. That is a real friction point for anyone scripting against the API first.

Two more environment comments matter. DEBUGBAR_ENABLED disables CSP when enabled, and LOG_VIEWER_ENABLED cannot be turned on in production; enabling it requires switching APP_ENV to local. Both are documented as trade-offs rather than bugs, but they mean a production install and a debugging install are configured differently, and you should not blur the two.

Finally, the README advises against APP_DIR, the setting for running Lychee in a subfolder. The project's own position is that you should not. If your deployment plan depends on a subpath, reconsider the plan.

## Lychee Compared with Nextcloud Memories and Immich

The closest comparison is Nextcloud with its Memories app. Nextcloud is a general collaboration platform where photos are one module among files, calendars and contacts. Lychee is a photo library and nothing else. If you already run Nextcloud, adding a photo view is cheaper than standing up a second stack with its own database. If you do not, you are adopting a much larger system to get a gallery, and Lychee's narrower scope is the argument in its favour.

Immich is the other obvious reference point, and the difference in approach is architectural. Immich is built around machine learning features such as face recognition and semantic search, and it is written in TypeScript and Node. Lychee is a PHP and Laravel application with a Vue frontend, and its dependency list shows Leaflet and mapping rather than an ML pipeline. If your priority is automatic face grouping, the two projects are solving different problems. If your priority is a browsable, shareable album structure on a PHP host you already pay for, Lychee is the simpler fit.

The licence difference is also concrete. Lychee's core is MIT, which is permissive and places few obligations on how you deploy or modify it. The README separates the Supporter Edition from the free core, so check which features sit behind that line before you commit. This is not legal advice; read the LICENSE file and the Supporter Edition page yourself.

## Maintenance Cost, Licence, and What to Check Before You Commit

The last push to the repository was on 2026-09-23, and the most recent release listed is v7.8.5 from 2026-09-18. The repository is not archived. That is a live project with a steady patch cadence, and the practical cost of that cadence is periodic image updates and the migrations that come with them.

The upgrade cost is not zero, and the version 7.0 notice is the proof. Major versions can change the Docker image in ways that require you to edit your compose file. Budget for reading the upgrade guide at lycheeorg.dev/docs/administration/upgrade/ each time a major version lands, not just each time a patch does.

The licence is MIT for the core, which is about as unencumbered as open source gets. The Supporter Edition is a separate offering with its own page and its own terms, and the README does not enumerate which features move behind it. Before you build a workflow around a specific feature, confirm whether it lives in the free core or the Supporter Edition. Read the LICENSE file in the repository root for the exact terms.

One more thing the repository tells you about the project's own process: the README states that AI-assisted contributions are permitted, with guidelines in docs/Contribute.md and AGENTS.md describing a Specification-Driven Development workflow. That is unusual enough to mention. It means the contribution process has documented rules for generated code, and if you plan to send patches, read those files before you open a pull request.

## Conclusion

Adopt Lychee if you want a photo library you control, you are comfortable running a database-backed container stack, and you can follow the upgrade guide when major versions land. Skip it if you need a hosted service with no server to run, or you cannot commit to database and image backups before you upload. Verify three things first: that your host meets the documented PHP 8.4 or 8.5 requirement, that you have generated an APP_KEY, and that you have read the version 7.0 upgrade guide before touching an existing install.

## FAQ

### How do I install Lychee on Linux?

The README's quickest route is to download docker-compose.minimal.yaml with curl and run docker compose -f docker-compose.minimal.yaml up -d, then open http://localhost:8000. For a fuller deployment the README provides a compose file with a MariaDB 11 service and health checks. Source installs require PHP 8.4+, Composer and npm.

### How do I use Lychee once it is running?

The README states that after starting the stack you open http://localhost:8000 in your browser, where you upload, manage and share photos. The README does not walk through the interface beyond that, and points to the documentation at lycheeorg.dev/docs/ for detailed configuration and update instructions.

### Does Lychee need an APP_KEY, and how is it generated?

Yes. The README's compose example comments show that you generate the key with echo "base64:$(openssl rand -base64 32)" and set the result as APP_KEY, in the form base64: followed by the generated value. The .env.example file ships with APP_KEY empty, so it must be filled before a source install will run.

### What changed in Lychee version 7.0?

The README's upgrade notice states that version 7.0 introduces significant changes on the docker image and directs readers to the upgrade guide at lycheeorg.dev/docs/administration/upgrade/ for instructions on upgrading from previous versions. The README does not describe those changes in detail or document a rollback procedure.

### What are the server requirements for Lychee?

The README's PHP badge names PHP 8.4 and 8.5, and the source installation route requires PHP 8.4+, Composer and npm. The Docker route bundles its own runtime, with the Dockerfile describing a multi-stage build on Laravel Octane and FrankenPHP. The README also notes legacy images that use nginx as the base instead.

### Is Lychee free and open source?

The core is MIT licensed, and the README describes Lychee as a free, open-source photo-management tool. The project also offers a Supporter Edition with additional functionality on a separate page, so check which features belong to which before you plan around a specific one.

## Sources

- [License: MIT](https://github.com/LycheeOrg/Lychee/blob/master/LICENSE)
- [LycheeOrg/Lychee on GitHub](https://github.com/LycheeOrg/Lychee)
- [Project website](https://lycheeorg.dev)
- [README](https://github.com/LycheeOrg/Lychee/blob/master/README.md)
- [Releases](https://github.com/LycheeOrg/Lychee/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lycheeorg-lychee
