guides

Migrating from Plex to Jellyfin

Already running Plex and thinking about switching to Jellyfin? You don’t have to re-rip anything or move any media. Both point at the same folder on the same NAS. What actually needs migrating is your watch history: what’s been watched, what’s in progress, and your ratings. This covers that, using a tool built for exactly this job.

A Synology DiskStation NAS unit
A Synology DiskStation NAS. Photo: DYVER, CC BY-SA 4.0.
Written for JellyPlex-Watched (luigi311/JellyPlex-Watched on GitHub), running via Container Manager on DSM 7.2. Check the project’s repo for the current compose file before you start. Sync tools like this get updated often, and we’ll revise this if the steps change.

Step 1. Install Jellyfin first, pointed at the same media folder

If you haven’t already, follow the Jellyfin install guide and map it to the exact same /volume1/media path Plex is using. Let Jellyfin finish its library scan before moving on. The sync tool matches items by filename and metadata provider ID, so both servers need to know about the same files first.

Step 2. Get a Plex token

Open Plex Web, play any item, then ⋮ menu → Get Info → View XML. The URL that opens contains X-Plex-Token= followed by your token. Copy everything after the equals sign. This is Plex’s own documented way to find it, no third-party tool needed.

Step 3. Get a Jellyfin API key

In Jellyfin, go to Dashboard → API Keys → +, name it something like jellyplex-sync, and copy the generated key.

Step 4. Set up JellyPlex-Watched

Make a docker/jellyplex-watched folder, and inside it a .env file:

PLEX_BASEURL=http://YOUR_NAS_IP:32400
PLEX_TOKEN=your-plex-token-from-step-2
JELLYFIN_BASEURL=http://YOUR_NAS_IP:8096
JELLYFIN_TOKEN=your-jellyfin-api-key-from-step-3
SYNC_INTERVAL=60
DRYRUN=True

Then in Container Manager → Project → Create, point it at that folder with this compose file:

services:
  jellyplex-watched:
    image: luigi311/jellyplex-watched:latest
    container_name: jellyplex-watched
    env_file: .env
    restart: unless-stopped
DRYRUN=True makes the tool log what it would sync without changing anything in Jellyfin. Deploy it this way first and read the container logs. Confirm it’s matching your actual titles before you let it write.

Step 5. Go live

Once the dry run looks right, meaning real titles, sensible matches, and no wall of “no match found” errors, edit .env to DRYRUN=False and redeploy. With SYNC_INTERVAL=60 it re-syncs every 60 minutes, which is plenty to keep both servers agreeing on watch state while you run them side by side.

This tool matches by filename and metadata provider ID, and it isn’t perfect. Odd file naming, obscure titles, or anything missing a proper IMDb/TMDb match can slip through. Spot-check a handful of recently watched titles in Jellyfin after the first real sync rather than assuming it all came across.

Step 6. Decide how long to run both

No rush to cut Plex off. Keep both running against the same media folder with the sync tool bridging watch state, for however long it takes everyone in the house to actually switch. When you’re ready, stop the Plex container and remove the sync tool. The media files are untouched either way.

A full migration without touching a single media file or losing years of watch history. The only thing that moved was metadata.

Leave a comment

Your email address will not be published. Required fields are marked *