# swiparr: A Tinder Style Queue for Deciding What to Watch Together

> Swiparr is an MIT licensed TypeScript app that turns the group decision about what to watch into a swipe session, working with Jellyfin, Emby, Plex or TMDB as the catalogue and letting a group agree by rule rather than by argument. It suits households with a media server who want the decision to take minutes.

**m3sserstudi0s/swiparr** — Swipe on what to watch next.

- Repository: https://github.com/m3sserstudi0s/swiparr
- Website: https://swiparr.com
- Stars: 800 · Forks: 27
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/m3sserstudi0s-swiparr

## The problem it is built around

The pitch is a single sentence: Swipe on what to watch next. The problem it names is the dreaded what should we watch question, described as 30 minutes of deliberation that ends with watching the same show again. The approach is to turn discovery into a game-like experience, to find content everyone in the group actually wants to watch, to make group decisions in minutes rather than hours, and to work with existing media libraries or standalone with no server at all. It describes itself as like Tinder for movies, but smarter, and the works for groups part is the differentiator rather than the swiping itself. The topics attached to the repository include arr, home-lab and movies-streaming, so the intended home is a self-hosted media server setup.

## Four catalogue providers with very different maturity

The provider support is where the honesty is. Jellyfin has full native integration and is the reference target. Emby and Plex are both marked as experimental support that is improving, which is a fair way of saying they work but are not finished. TMDB requires no media server at all and works standalone, so it is the option for a group without a server, and it needs an API read-only token plus an optional default region for availability and certifications. The multi-provider support in the feature list means the same session logic sits on top of whichever catalogue you point it at, and the Vercel deployment defaults to the TMDB provider with the provider lock enabled, which you can set to false to configure the provider at run time.

## Sessions, match rules and how a group agrees

A session is the unit of play. Creating or joining takes seconds with no complex setup, and the rules are what stop it becoming a free-for-all. You choose between any two people and everyone must agree, which is the difference between a relaxed evening and a unanimous vote. Session controls let you limit likes, dislikes or the total number of matches, so a session can be capped at three picks for a single evening or left open. The stated purpose of the matching is automatic: it finds content everyone in the group will enjoy, which is a stronger claim than a shared queue, and the review-again point is that the swipe interface is a familiar card-based design rather than an original mechanic.

## Watchlist write-back and the provider plugin dependency

Favourites can be saved back to your media server, and the Jellyfin configuration exposes the choice explicitly with JELLYFIN_USE_WATCHLIST, which selects the Watchlist or the Favorites collection, with the comment that the Watchlist path needs a plugin. That is a small configuration line carrying a real dependency, and it is the sort of detail that decides whether the feature works on your server. The Emby and Plex setups show no equivalent setting in the documented variables, which is consistent with their experimental status. The internal URL is required for each provider and the public URL is optional, which suggests the internal URL is used for server-side calls and the public one for the links handed to clients.

## Running it with Docker Compose

Self-hosting is documented with a compose file you write yourself, and the service block is short because the defaults cover most of it.

```yaml
services:
  swiparr:
    image: ghcr.io/m3sserstudi0s/swiparr:latest
    container_name: swiparr
    restart: unless-stopped
    environment:
      - PROVIDER=jellyfin  # or plex, emby, tmdb (or set PROVIDER_LOCK to "false")
      - JELLYFIN_URL=http://your-jellyfin:8096 # adjust to provider, none without server lock
    volumes:
      - ./swiparr-data:/app/data
    ports:
      - 4321:4321
```

Then you start it and open the port.

```bash
docker compose up -d
```

The volume mount is what persists the SQLite database across container replacements, and the port mapping exposes the app on 4321. The Docker CLI route is given as an alternative with the same values expressed as flags, mounting the same data directory and passing the provider and URL as environment variables to the same ghcr.io image.

## The configuration surface and where the secrets live

The configuration reference separates provider settings from application settings, and the application block is worth reading because it defines what the app trusts. AUTH_SECRET is auto-generated on boot or build when you do not provide one, by a script called scripts/ensure-auth-secret.cjs, and persisted in the database. USE_SECURE_COOKIES must be true for HTTPS. PORT defaults to 4321 and HOSTNAME to 0.0.0.0. The database is either a SQLite file at a path under the data directory or a Turso URL with an auth token. There is an admin username variable that globally auto-grants admin privileges, and a base path setting that is build-time only, because the prefix has to be baked into the asset URLs. The base path detail comes straight from the Dockerfile, where the argument is passed at build time so Next.js can write the correct prefix into its static asset paths.

## A Next.js app with Drizzle, SQLite and a dark component stack

The stack is visible in the package manifest and the Dockerfile. It is a Next.js application on Node 24 or newer, with Drizzle ORM handling the database, drizzle-kit for generating and pushing migrations, and LibSQL as the client, which is what lets the same code talk to a local SQLite file or a remote Turso database. Sessions use iron-session. The interface is React with Radix UI primitives for the accessible parts, Base UI, Framer Motion and React Spring for the card motion, TanStack Query for data fetching, Tailwind and shadcn-style components, with Vite and PostCSS in the tooling. The Docker build is a multi-stage one on node:24-alpine that installs dependencies, builds, and then copies only the Next standalone output, the static assets and the Drizzle migration files into the runtime stage, running as a non-root nextjs user in a group with uid 1001.

## Deployment options, maintenance and the trade-offs

There are three ways to run it. Swiparr Global at swiparr.com is free to use and community supported, described with a hopeful caveat. Vercel deployment is one click, with the Turso integration providing the database by default, and the security note that AUTH_SECRET is auto-generated during the build and persisted in the database when not provided. Docker is the full-control option. On maintenance, the last push was on 2026-07-22, which also shipped v1.5.1, following v1.5.0 on 2026-06-26 and v1.4.1 on 2026-06-25, and the repository publishes no separate release notes beyond the tagged versions and a CHANGELOG.md. The alternative approach to this problem is the plain one, a shared watchlist and a chat message asking who wants what, which costs nothing but leaves the group with no rule for disagreement and no record of what was rejected. Swiparr replaces that with a session, a rule and a swipe, and the price is an app everyone has to open.

## Conclusion

swiparr fits a household or friend group with a shared media server who keeps losing evening time to the same debate, and who want a rule for agreement rather than a negotiation. It is the wrong choice if your catalogue is only on one streaming service with no self-hosted server, since TMDB is the closest fit and needs an API token, and the wrong choice if the group will not open an app. Before you self-host it, decide which provider to lock to and whether the watchlist write-back plugin is available, because Jellyfin's native integration is the one described as complete.

## FAQ

### Which media servers can swiparr work with?

Jellyfin has full native integration, Emby and Plex have experimental support that is improving, and TMDB works standalone with no media server at all, requiring only an API read-only token and optionally a default region.

### How do group members agree on something to watch?

You create or join a session and swipe on cards. The match rule is configurable, either any two people or everyone must agree, and session controls can limit likes, dislikes or the total number of matches.

### How do I self-host swiparr with Docker?

Write a compose file using the ghcr.io/m3sserstudi0s/swiparr:latest image, set PROVIDER and the provider URL, mount ./swiparr-data to /app/data and map port 4321, then run docker compose up -d and open http://localhost:4321.

### Can swiparr save what you pick back to your media server?

Yes, watchlist sync is supported. On Jellyfin the choice between the Watchlist and Favorites is set with JELLYFIN_USE_WATCHLIST, and the Watchlist path needs a plugin installed on the server.

### Does swiparr need a database server?

No. The default is a SQLite file under the data directory, set with DATABASE_URL=file:/app/data/swiparr.db, and the same LibSQL client can point at a remote Turso database with an auth token when you want one.

## Sources

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

---

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