VueTorrent: a web interface for qBittorrent, not a second client
The sleekest looking WEBUI for qBittorrent made with Vuejs!
At a glance
- What is it?
- VueTorrent replaces the page qBittorrent serves in the browser while still calling the same WebAPI, so automation such as the *arr stack is unaffected. It is a Vite and Vuetify project, and its installation section is a wiki link rather than a command.
- Who is it for?
- VueTorrent suits anyone who wants the qBittorrent surface on a phone or on a dark themed dashboard without disturbing the automation stack, and it is a poor fit if you want a packaged client or a one line install.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Vue, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- VueTorrent/VueTorrent7,051 ★ · +79
| Repository | 2026-09-23 | 2026-11-14 |
|---|---|---|
| VueTorrent/VueTorrent | 7k | 7.1k |
79 Stars in the last 52 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
A visual skin over the WebAPI, not a second torrent client
VueTorrent calls qBittorrent's WebAPI and renders the result in the browser. The project is explicit about what that means: a WebUI is a visual skin, and anything compatible with the classic qBittorrent WebUI keeps working no matter which one you loaded. That is the entire compatibility argument. Sonarr, Radarr and the rest of the *arr stack talk to qBittorrent, not to the page, so swapping in VueTorrent changes what you look at and nothing about how your automation authenticates or polls.
The front end is a normal Vue project rather than a bundle of hand written DOM. package.json pins vue at ^3.5.44, vuetify at ^4.2.6, vue-router at ^5.2.0 and pinia for state, with vue-i18n at ^11.4.16 carrying the interface languages. Charts come from apexcharts through vue3-apexcharts, which is what draws the transfer graphs. dompurify, axios, dayjs and uuid fill in sanitising, requests, dates and keys.
The feature list claims optimization for the latest version of qBittorrent, and preferences for qBittorrent Enhanced Edition are also handled.
Host header validation blocks localhost until you turn it off
Getting a dev environment talking to a local qBittorrent takes one setting that is easy to miss. The development list ends with two requirements: open the WebUI on localhost with the default credentials, and make sure Host header validation is disabled in the qBittorrent preferences. The default credentials step points at issue 1720 for the detail.
The install and start commands are the ordinary Vite loop:
npm install
npm startnpm start is an alias for vite, and npm run dev does the same thing. Two lint scripts sit alongside them, npm run lint running eslint and npm run lint:fix passing --fix so eslint rewrites what it can.
For something to talk to, the compose file is marked optional in the same list and starts a qBittorrent container rather than the interface.
The public demo serves five fake torrents and refuses downloads
The hosted demo at vuetorrent.github.io/demo is built to look full without being connected to anything. A note next to the link says this version is not connected to a qBittorrent instance and that downloading torrents or changing preferences will not work. Anyone evaluating the interface from that page is reading generated records.
The same mode exists on your own machine. The .env.sample at the repository root is three settings:
VITE_QBITTORRENT_TARGET=http://localhost:8080
VITE_USE_MOCK_PROVIDER=false
VITE_FAKE_TORRENTS_COUNT=5The first line is where the frontend looks for qBittorrent. The second is the mock switch, shipped as false, and the third sets how many fake entries the mock serves. The build scripts split the same way: build-demo passes -m demo to vite build, and preview-demo runs vite preview with the same mode. Copy .env.sample to .env before starting if you want those values changed.
Multi-select on the Dashboard lives on Ctrl-click and Shift-click
Selecting torrents in bulk takes three separate gestures, and all of them are spelled out. Ctrl-click a torrent card to enter multi-select mode. Hold Shift and click to select every torrent between the last selected card and the one you clicked. Ctrl-A selects everything while no dialog is open.
Escape is overloaded on purpose. It dismisses any open dialog, and when nothing is open it first unfocuses the search input, then unselects all torrents if pressed again. Deletion uses Delete, which is Fn-Backspace on a Mac. Search takes Ctrl-F, and pressing it a second time hands over to the browser's own find in page.
A Mac keymap is built in, so Cmd stands in for Ctrl throughout. That is the only platform difference the project handles explicitly instead of leaving to the user, and it says something about who this is written for.
The compose file brings up qBittorrent, not VueTorrent
The docker-compose.yml in this repository does something its name does not suggest: it starts qBittorrent. The single service is called qbit, it uses the linuxserver/qbittorrent:latest image, and VueTorrent arrives inside that container as a mod:
environment:
- PUID=1000
- PGID=1000
- UMASK_SET=022
- TZ=Europe/London
- WEBUI_PORT=8080
ports:
- '8080:8080'
- '6881:6881'
- '6881:6881/udp'A DOCKER_MODS variable pulls ghcr.io/vuetorrent/vuetorrent-lsio-mod:latest into the container, which is how the interface gets installed on a LinuxServer.io style image.
Two ports are published, 8080 for the WebUI and 6881 on both TCP and UDP for the BitTorrent protocol. Because the mod is referenced by its :latest tag, there is no version to pin here and a rebuild can pick up a build other than the one you tested.
FROM scratch, one copied binary, no runtime inside
The Dockerfile in the repository is two instructions and no runtime at all. There is no base image and no node in the result:
FROM scratch
COPY --chmod=555 /vuetorrent /vuetorrentThat shape only works if the compiled output already sits on the build machine, which tells you where the real work happens. The npm scripts do it: build runs vue-tsc and then vite build, check-build runs vue-tsc on its own as a type check gate, and a script named postbuild.cjs runs automatically after every build.
So the deliverable is a static bundle of a Vue single page app. VueTorrent ships assets and a WebAPI client, and qBittorrent stays the process that does the downloading.
Version numbers come from release-please, not from a person
Version numbering is delegated to a tool. The repository carries .release-please-manifest.json and release-please-config.json next to CHANGELOG.md, which is the release-please arrangement where commit messages drive the version bump and the changelog entry rather than somebody editing files by hand. package.json reports version 2.36.1, matching the v2.36.1 tag published on 2026-09-29, about an hour and a half after v2.36.0 on the same morning.
The rest of the tooling follows the same pattern of small explicit scripts. TypeScript has tsconfig.json and tsconfig.node.json, the build runs through vite.config.ts, and linting is a flat config in eslint.config.mjs with prettier kept separate through .prettierrc.json and .prettierignore. Tests live in tests/ and use vitest, with @vitest/coverage-v8 behind the coverage variant, @pinia/testing for store tests and @faker-js/faker to generate records.
package.json also pins the package manager itself at [email protected], so a clone installs against a known npm version.
The companion backend stores settings and calls itself unfinished
VueTorrent has a companion service it does not need. The README points at a separate repository, vuetorrent-backend, and describes it as a work in progress that is not required to use VueTorrent. Its stated job is to store server side settings, which is precisely what a browser cannot do on its own for preferences meant to outlive a cache.
Everything else stays inside qBittorrent. Torrent actions cover add, remove, pause, resume and rename, selective file download, and views for info, trackers, peers, content, tags and categories, plus a search box for finding new torrents from the interface. Session stats show download and upload speed, session totals and free space. The two additions over the stock WebUI are a mobile layout installable as a PWA and a configurable dashboard where you choose which torrent properties appear for busy and completed torrents.
The gap worth naming is documentation. Installation is one link to the wiki, and configuration questions are expected to land there or in the FAQ page.
Editorial conclusion
VueTorrent suits anyone who wants the qBittorrent surface on a phone or on a dark themed dashboard without disturbing the automation stack, and it is a poor fit if you want a packaged client or a one line install. Before deploying, check three things: that host header validation is switched off on the instance you point VITE_QBITTORRENT_TARGET at, that you are comfortable tracking a mod pinned to :latest, and that you can live without the server side settings store, which the project calls a work in progress.
Frequently asked questions
How do I install VueTorrent?
The installation section is a link to the project's wiki rather than a set of commands. For a Docker setup, the repository's compose file pulls ghcr.io/vuetorrent/vuetorrent-lsio-mod:latest into a linuxserver/qbittorrent container through the DOCKER_MODS variable, with the interface served on port 8080.
How do I install VueTorrent with Docker?
The compose file in the repository defines one service named qbit from linuxserver/qbittorrent:latest, and DOCKER_MODS points at the VueTorrent lsio mod so the interface is installed inside that container. It publishes 8080 for the WebUI and 6881 on TCP and UDP. The development notes mark the compose step as optional.
How do I use VueTorrent against a local qBittorrent?
Point VITE_QBITTORRENT_TARGET at your instance, copy .env.sample to .env to edit it, then start the Vite dev server with npm start. Two qBittorrent side settings matter: open the WebUI on localhost with the default credentials, and disable Host header validation in the qBittorrent preferences.
What is the difference between VueTorrent and the qBittorrent WebUI?
VueTorrent is a replacement for the page qBittorrent serves, not a separate client, and it calls the same WebAPI. The project states that anything compatible with the classic qBittorrent WebUI works regardless of which WebUI you chose. Over the default it adds a PWA installable mobile layout and a configurable dashboard.
What is the best web interface for qBittorrent?
VueTorrent is one of them, and the project's own position is that WebUIs are interchangeable: VueTorrent uses qBittorrent's WebAPI, so anything written against the classic WebUI keeps working whichever skin is loaded. What you are choosing between is presentation, plus extras such as keyboard shortcuts and mobile support.
Official sources
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.
[](https://hysenlabs.com/projects/vuetorrent-vuetorrent)Star history chart for your README
[](https://hysenlabs.com/projects/vuetorrent-vuetorrent)Was this useful?