Self-hosted service
Xyphyn/photon avatar
Xyphyn/photon

Photon is a Svelte front end for Lemmy and PieFed instances you do not run

A faster, prettier, and nicer fediverse client

558 stars64 forksSvelteAGPL-3.0

At a glance

What is it?
Xyphyn/photon is a web app for the fediverse that connects to an existing Lemmy or PieFed instance and replaces the default lemmy-ui front end, built on SvelteKit with a reported JavaScript payload 2.8 times smaller. It is self-hostable through a container image or a Bun or Node build, and it is licensed AGPL-3.0, which matters for anyone running it as a service.
Who is it for?
Photon is the right pick for an existing Lemmy or PieFed instance that wants a faster, more configurable front end, and for anyone who wants to run one on their own infrastructure with a container image or a two-command build. It is the wrong pick if you have no instance yet, since the front end has nothing to talk to, and its AGPL-3.0 licence needs a look before you put it behind a public service.
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 11 days ago.
What is it written in?
Mainly Svelte, 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 front end, not a Lemmy server

Photon is described as a web app for the fediverse with helpful features and a nice UX, and the important structural point is in the self-hosting section. You self-host a Photon frontend server for your Lemmy instance, or independently for any instance. In other words, Photon is a client and a web tier, not a federated server. It does not implement the ActivityPub side of Lemmy, it does not store your posts, and it does not replace the backend. It talks to an instance over its API and renders what it finds, and the README is explicit that if you want to use it as a drop-in replacement as the primary frontend, the instance must have already been set up. That constraint shapes everything about how you would evaluate it. The audience is two groups, an instance operator who wants a different look and behaviour for their community, and a user who wants a client for a public instance. The feature list reflects that, with multi-account switching, infinite scroll, customisation, support for Lemmy and PieFed, multiple languages through a community translation effort, and a Svelte base chosen for responsiveness.

SvelteKit, a smaller payload and a heavy dependency list

The stack is visible in package.json, which names the package photon-lemmy at version 2.4.3 under an AGPL-3.0-only licence. The framework is Svelte with @sveltejs/kit, built by vite with the Svelte vite plugin, and styled with tailwindcss 4, including the container queries plugin. The API side uses lemmy-js-client and openapi-fetch, and post rendering uses marked with marked-linkify-it and linkify-it. The feature claims in the README include a 2.8x smaller JavaScript payload compared to lemmy-ui, and optimized image loading where possible to save bandwidth, both of which are consequences of the same choice, a compiled Svelte front end rather than a heavier client runtime. The dependency list is long and includes some things worth knowing about. svelte-infinite-scroll backs the infinite scroll, sveltekit-i18n handles the multiple languages, ua-parser-js and trap-focus-svelte handle browser detection and focus management, and @dicebear provides avatar fallbacks. The android/ directory and capacitor.config.ts show that a Capacitor based Android application is built from the same code, with the Capacitor Android, app and haptics plugins in the dependency set.

Running the container image on port 8080

The quickest path is the published image, and the README recommends Docker Compose if you plan to pass a lot of environment variables. The images live at ghcr.io/xyphyn/photon, and an unconfigured instance can be started like this:

bash
docker run -p 8080:3000 ghcr.io/xyphyn/photon:latest

Note the port mapping. The container listens on 3000, which the Dockerfile exposes, and the host side is published on 8080. There is also a runtime choice baked into the image tags. The default images run a Bun server, and the README notes that if you encounter strange issues with the default images you can use the alternative Node server by appending -node to the image version, giving an example tag of ghcr.io/xyphyn/photon:v2.0.0-node. The Docker build itself is a multi-stage file with separate Bun and Node builder stages and two final images, and the Node variant is the one that ends up running the server by default:

dockerfile
FROM node:20-alpine AS node
USER node
WORKDIR /app
EXPOSE 3000
CMD ["node", "build/index.js"]

The Bun image is built the same way from oven/bun:1.2.9-alpine with the command bun build/index.js.

Building natively with Bun or Node

If you would rather build from source, the README gives two paths, and the difference is the adapter you select with the ADAPTER variable. The Bun path is the faster one:

bash
bun install
ADAPTER=bun bun run build

# run the built server
bun build/index.js

The Node path is described as slower but with better support:

bash
npm install
ADAPTER=node npm run build

node build/index.js

The clone step is a single command:

bash
git clone https://github.com/xyphyn/photon && cd photon

The ADAPTER value selects the SvelteKit adapter, and the dependency list shows the options that are available in the tree, with adapter-node, adapter-cloudflare, adapter-static and adapter-auto alongside svelte-adapter-bun-next, the package that provides the Bun target. The README calls the Bun server faster and the Node server better supported, and that trade-off shows up again in the troubleshooting section. Tests run under vitest, with the test script mapped to it, and linting and formatting are handled by eslint with eslint-plugin-svelte and prettier with prettier-plugin-svelte.

Configuration lives in PUBLIC_ prefixed environment variables

Photon lets you configure the default client settings and more, and the variables follow a strict convention. Configuration environment variables are prefixed with PUBLIC so that clients can use them, and the README notes the reason, that no sensitive data can be leaked. If you are hosting Photon for a Lemmy instance you will almost certainly want PUBLIC_INSTANCE_URL, the domain the browser sends API requests to, and PUBLIC_INSTANCE_TYPE, which takes lemmyv3 or piefedalpha and defaults to lemmyv3. The README says if your instance is running PieFed you must set that option to piefedalpha, otherwise you do not need to do anything. PUBLIC_SSR_ENABLED is the switch that makes page requests render server side first, which allows search engine indexing and basic non-JavaScript usage, and it is what you need if you care about the front end being indexable. It brings with it PUBLIC_INTERNAL_INSTANCE, the domain the server itself calls. PUBLIC_MIGRATE_COOKIE is the one that matters for existing users, since it migrates logins from lemmy-ui so people do not have to sign in again. There is also PUBLIC_THEME, a JSON blob you can export from Photon, and RECOMMENDED_INSTANCES, a comma separated list of instance domains shown as recommended on the sign-up page. User level defaults live in the defaultSettings object in src/lib/settings.ts, and PUBLIC_LOCK_TO_INSTANCE=false is what lets users pick any instance they want.

Where Photon is the wrong tool

Three cases stand out. The first is the obvious one, a deployment with no Lemmy or PieFed instance behind it, because Photon is only a front end and the README requires the instance to be set up already. The second is the runtime and reverse proxy combination, and the README is unusually candid about it. The FAQ entry records errors about header buffer size in NGINX, points to a specific comment on issue 253 for a fix, and offers the other option of using the Node server instead of the Bun server. That is a real operational trap, because the recommended runtime is also the one that produces the error in that configuration. The third is licensing and lifecycle. The repository is licensed AGPL-3.0, which is a clearly different obligation from the permissive licences of most web apps, and it obliges you to look at the terms yourself if you intend to run Photon as a service for other people rather than for your own instance. There is also a social cost to running a stale copy, since the README asks operators to keep instances mostly up to date and says instances that stay out of date will be removed from the public list. The alternative to Photon is the front end your instance already has, lemmy-ui, and the difference in approach is the whole point of the project: Photon is a compiled Svelte client with a smaller payload and PieFed support, and lemmy-ui is the default interface that ships with the instance software. If your users are content with that, there is no reason to add Photon.

Maintenance pace, public instances and the AGPL question

The repository is not archived and the last push was on 2026-10-12. The published releases are v2.4.3 on 2026-07-30, v2.4.2 on 2026-07-17 and v2.4.1 on 2026-07-15, so the release cadence is frequent enough that a self-hoster is expected to pull images regularly rather than pin a version for the year. There is a public instance list in the README with phtn.app as the official instance, which the README says will get updates instantly, alongside community instances in Singapore, Indonesia, Austria and Turkey. Anyone can propose an instance by opening an issue or a pull request, and the rule for staying listed is that the instance must not fall too far behind. The list of features also carries the project's own framing, since the README says Photon supports nearly everything lemmy-ui does, which is the benchmark a self-hoster will be measured against. The project is funded by donations, and the licence file in the repository is the AGPL-3.0, so anyone offering Photon as a service to third parties should read that licence rather than assume the terms of a typical permissive web application.

Editorial conclusion

Photon is the right pick for an existing Lemmy or PieFed instance that wants a faster, more configurable front end, and for anyone who wants to run one on their own infrastructure with a container image or a two-command build. It is the wrong pick if you have no instance yet, since the front end has nothing to talk to, and its AGPL-3.0 licence needs a look before you put it behind a public service. Before deploying, confirm whether the Bun or Node runtime suits your reverse proxy, since the README records an NGINX header buffer problem specific to the Bun server, and note the last push was on 2026-10-12 with the newest release at v2.4.3 from 2026-07-30.

Frequently asked questions

How do I run Photon with Docker?

The images are published at ghcr.io/xyphyn/photon, and an unconfigured instance on host port 8080 is started with docker run -p 8080:3000 ghcr.io/xyphyn/photon:latest. The README recommends Docker Compose if you will pass a lot of environment variables.

What is the difference between the Bun and Node versions of Photon?

The Bun server is described as faster, while the Node server is slower but has better support. You select one with the ADAPTER variable at build time, for example ADAPTER=bun bun run build or ADAPTER=node npm run build, and you can also append -node to a Docker image version to get the Node based image.

Which environment variables does Photon need for a Lemmy instance?

The README highlights PUBLIC_INSTANCE_URL for the domain the browser calls, PUBLIC_INSTANCE_TYPE which must be set to piefedalpha for a PieFed instance, and PUBLIC_SSR_ENABLED if you want server side rendering and search engine indexing, which then also needs PUBLIC_INTERNAL_INSTANCE. PUBLIC_MIGRATE_COOKIE migrates logins from lemmy-ui.

Does Photon need its own Lemmy instance?

No. You self-host a Photon frontend server for your Lemmy instance, or independently for any instance, so Photon can point at an existing instance. If you want to use it as the primary front end, the README says the instance must have already been set up.

Official sources

  1. License: AGPL-3.0
  2. Project website
  3. README
  4. Releases
  5. Xyphyn/photon on GitHub
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/xyphyn-photon.svg)](https://hysenlabs.com/projects/xyphyn-photon)

Was this useful?