Bazarr+ is a drop-in replacement for upstream Bazarr. It uses a compatible database with additional columns added on first run, the same config files, and the same volume paths. Switching takes about five minutes.
The v2.4 additions are additive and non-destructive. Your existing settings, language profiles, providers, and the shared OpenSubtitles-compatible token all carry over. Schema migrations run automatically on first boot, and the old shared compat token is auto-seeded as an "Unlimited Default" key in the new Distribution Hub, so existing integrations keep authorizing without changes.
Back up your config
Before making any changes, stop Bazarr and copy your entire config directory. This is the directory you mounted as /config in your existing Bazarr container. Stop it first: Bazarr writes to its SQLite database while it runs, and a copy taken in the middle of a write may not open later.
BACKUP=./config-backup-$(date +%Y%m%d-%H%M%S)
if [ -e "$BACKUP" ] || [ -e "$BACKUP.partial" ]; then
echo "$BACKUP or $BACKUP.partial already exists, so nothing was stopped or copied"
elif docker compose down; then
cp -a ./config "$BACKUP.partial" &&
mv "$BACKUP.partial" "$BACKUP" &&
echo "Backup: $BACKUP"
else
echo "Bazarr did not stop, so nothing was copied"
fi
The copy only runs if Bazarr stopped. If docker compose down reports an error, fix that first and run the commands again. Each run makes a new folder named with the date and time, so a second backup never lands inside the first, and you can restore from it if anything goes wrong. The config directory contains your SQLite database (db/bazarr.db), settings, logs, and cached data. The last line prints the folder name, for example config-backup-20260924-143015. Note it: the revert steps below ask for it. If the copy fails partway, for example on a full disk, that line is missing and the unfinished copy is left in a folder ending in .partial. It is not a backup: remove it once you have fixed the cause, then run the commands again.
Container swap process
Bazarr is still stopped from the backup step. The actual swap is just changing the Docker image name in your compose file.
-
Update the image in your
docker-compose.yml. Change the image line from the upstream image to the Bazarr+ image:Before → After# Before (upstream) image: lscr.io/linuxserver/bazarr:latest # or image: ghcr.io/morpheus65535/bazarr:latest # After (Bazarr+) image: ghcr.io/lavx/bazarr:latest -
Add the companion services. The only companion service recommended now is FlareSolverr, plus the optional AI translator. OpenSubtitles.org is a native Provider Hub plugin in v2.4: install it from the Marketplace, then point its FlareSolverr URL setting at the flaresolverr service below (
http://flaresolverr:8191/v1on a shared Docker network, orhttp://localhost:8191/v1with host networking, in which case also publish FlareSolverr's8191:8191port or run it on host networking too so 8191 is reachable on the host). There is no separate scraper container anymore.docker-compose.yml additions# Add these services: # Recommended for the OpenSubtitles.org and many other plugins. Set this container's # /v1 URL (http://flaresolverr:8191/v1) in the plugin's FlareSolverr URL. With host # networking use http://localhost:8191/v1 and add a "8191:8191" ports mapping below # (or run flaresolverr on host networking too) so 8191 is reachable on the host. flaresolverr: image: ghcr.io/flaresolverr/flaresolverr:latest container_name: flaresolverr restart: unless-stopped environment: - LOG_LEVEL=info healthcheck: test: ["CMD", "curl", "-sf", "http://localhost:8191/health"] interval: 30s timeout: 10s retries: 3 start_period: 60s # AI translation via OpenRouter (free tiers available) # Configure the API key in Settings > AI Translator ai-subtitle-translator: image: ghcr.io/lavx/ai-subtitle-translator:latest container_name: ai-subtitle-translator restart: unless-stopped ports: - 8765:8765 healthcheck: test: ["CMD", "curl", "-sf", "http://localhost:8765/health"] interval: 30s timeout: 10s retries: 3 start_period: 10s -
Start the new stack.
Shell
docker compose up -d
That is it. Open Bazarr+ in your browser and everything should be where you left it.
What changes
After the swap, you get all the Bazarr+ additions on top of your existing setup:
- Provider priority. A toggle in Settings > Subtitle Sources enables priority-ordered querying with early stop.
- Bulk operations. Series and Movies pages gain checkboxes and a batch action toolbar.
- Subtitle editor. A new "Edit" button appears next to each downloaded subtitle.
- AI translation. Translate subtitles into any language via OpenRouter models. Configure in Settings > AI Translator.
- Telemetry removed. All Google Analytics tracking code is gone. No data leaves your server.
- UI improvements. Navigation changes, keyboard shortcuts, and various polish throughout.
What stays the same
- Database. Your SQLite database is used as-is. Bazarr+ adds a few columns via Alembic migrations on first run (e.g. score_out_of, tvdbId), but these do not break backwards compatibility.
- Settings. All your provider accounts, language profiles, Sonarr/Radarr connections, and notification settings carry over.
- History. Your entire download and upgrade history remains intact.
- Subtitles. All previously downloaded subtitle files stay on disk, untouched.
- Scheduled tasks. Your scan intervals and other scheduled tasks continue as configured.
- OpenSubtitles-compatible token. The shared compat token from earlier versions is auto-seeded as an "Unlimited Default" key in the Distribution Hub, so any Jellyfin, VLSub, or custom client using it keeps working unthrottled.
External Integration has moved
One item changed location in v2.4. The old Settings > External Integration page is gone. Endpoint and token management for the OpenSubtitles-compatible API now lives in the Distribution Hub, and /settings/external redirects there. If you bookmarked or scripted against the old page, point it at the Distribution Hub instead. To recover the current shared token, use the "Reveal token" action on the Unlimited Default key.
Password upgrade notice
Upstream Bazarr stores passwords using MD5, which is insecure. On first login after the migration, Bazarr+ will transparently upgrade your password hash to PBKDF2 with 600,000 iterations. This happens automatically when you enter your existing password. No action needed on your part.
Reverting if needed
If you want to switch back to upstream Bazarr for any reason:
-
Stop Bazarr+ and restore your backup. Run
ls -d ./config-backup-*to list your backups and put the exact folder you made before migrating inBACKUP. A name ending in.partialis a copy that did not finish, and the commands refuse it. The commands check that folder exists, stop Bazarr+, copy the backup next to your config, and only then swap it in. If Bazarr+ does not stop, nothing is copied or moved. Your current config is moved to./config-bazarr-plus-YYYYMMDD-HHMMSS, not deleted: the name carries the time of the restore, and the last line prints where the config went, so reverting a second time never has anything to move out of the way first. If any step fails, the config you had stays where it is. If./config-restoreis already there, from an interrupted restore, the commands stop before anything else happens and delete nothing. Move that folder somewhere else, then run them again.ShellBACKUP=./config-backup-YYYYMMDD-HHMMSS # your backup folder's exact name MOVED=./config-bazarr-plus-$(date +%Y%m%d-%H%M%S) if [ ! -d "$BACKUP" ]; then echo "No backup folder at $BACKUP" elif [ "${BACKUP%.partial*}" != "$BACKUP" ]; then echo "$BACKUP is a copy that did not finish, so nothing was restored" elif [ -e ./config-restore ]; then echo "./config-restore is already there, so nothing was restored. Move it away, then run the commands again" elif docker compose down; then cp -a "$BACKUP" ./config-restore && mv ./config "$MOVED" && mv ./config-restore ./config && echo "Your config is now the backup; the config you had is at $MOVED" else echo "Bazarr+ did not stop, so nothing was restored" fi - Change the image back to the upstream image in your compose file.
- Start it. Run
docker compose up -d.
The backup puts everything back as it was before the migration, including your old password, so there is nothing to reset. Changes you made in Bazarr+ after migrating do not come back with it.
If you did not keep a backup and want to revert, there are a few things to be aware of. The password hash in config/config.yaml inside your config directory (./config/config/config.yaml in the commands above) under auth.password will be in PBKDF2 format, which upstream cannot read. Clear the password field to reset it. Additionally, the series_scores and movie_scores config sections are deleted by Bazarr+, gemini_key is migrated to a gemini_keys list, and the analytics section is removed.
Next steps
- Install Provider Hub plugins after your migrated instance is running
- Set up the Distribution Hub to issue named, tiered API keys for the OpenSubtitles-compatible endpoint
- Process subtitles with combined output, embedded-track scoring, and multi-engine sync
- Set up AI translation to use one of the new features that prompted the switch
- Getting Started for a full walkthrough of all configuration options