Pip vs Docker for open source data labeling right now
Two paths to Label Studio 1.23.0: pip in a venv, or the official image. Docker wins for most teams – isolation, the runtime maintainers actually ship (Alpine base as of 1.23.0), and no host Python version fights. Pip still makes sense for a laptop spike if you already sit on Python 3.10+ venvs.
This is a deploy guide only. No labeling walkthrough. Sources used throughout: install docs, GitHub releases, Docker Hub.
System requirements (as of 1.23.0)
Floors from the official install page before you pull:
| Resource | Minimum | Recommended |
|---|---|---|
| OS | Linux, macOS, Windows | Linux server or Docker Desktop |
| RAM | 8 GB | 16 GB |
| Disk | Fit your dataset | 50 GB production; ~2.3 GB per 1M SQLite tasks |
| Python (pip path) | >=3.10,<4 (package metadata) | 3.10-3.12 clean venv |
| Database | SQLite 3.35+ | PostgreSQL 14+ |
| Port | 8080 free | Remap with -p / –port |
| Browser | Modern | Latest Chrome |
Docs still say Python 3.8+ in places. pyproject.toml does not – install on 3.8/3.9 and deps break. Trust the package require, not the stale line.
Official downloads only
- PyPI:
pip install label-studio(1.23.0 stable as of the 1.23.0 release line; nightly tracks 1.24.0.dev on GitHub) - Docker:
docker pull heartexlabs/label-studio:latest– pin:1.23.0when you need a frozen tag on Hub - Source: github.com/HumanSignal/label-studio
Release notes for 1.23.0 call out Vector/VectorLabels, Data Manager filter copy/paste, and the Docker base move to Alpine. If you derive a custom image, apt-get lines die at build – switch to apk.
Install with Docker (recommended)
Create the data dir and fix ownership before the first run. Skip this and you get a PermissionError on media – the classic first-boot failure.
mkdir -p mydata
sudo chown :0 mydata
# or: sudo chown -R 1001:0 mydata
docker pull heartexlabs/label-studio:latest
docker run -it --name label-studio
-p 8080:8080
-v "$(pwd)/mydata:/label-studio/data"
heartexlabs/label-studio:latest
PowerShell volume: -v ${PWD}/mydata:/label-studio/data. Detached: -d. Host port remap: -p 9001:8080.
Turns out the container has run as non-root UID 1001 since 1.7.0. Host bind mounts still owned by your login user cannot write /label-studio/data/media. GID 0 on the directory (or 1001:0) fixes it – same pattern the troubleshoot docs and long-running GitHub threads describe.
After the Alpine switch in 1.23.0, any custom Dockerfile still calling
apt-get updatefails at build. Package lines need Alpineapkor the image never starts.
Default store inside the volume: SQLite (label_studio.sqlite3) plus media. Fine solo. Painful once three annotators share one laptop DB – that’s usually when Postgres enters the picture, not on day one.
Pip path (quick local)
python3 -m venv env
source env/bin/activate # Windows: envScriptsactivate
python -m pip install -U pip
pip install label-studio==1.23.0
label-studio start
Windows and lxml hate compiling from source. Grab a matching prebuilt wheel, install the .whl first, then retry pip install – the troubleshoot guide calls this out for a reason.
First-time configuration
Open http://localhost:8080. Create the first local account. That’s enough to log in.
Worth setting if you need them (Docker -e, or export for pip):
LABEL_STUDIO_PORT=9001LABEL_STUDIO_HOST=https://your.domain– wrong host breaks generated links and tunnels
No config file required for boot. Point at Postgres later via the store-data docs when SQLite disk or lock behavior gets noisy.
Verify the install works
Three checks. Done.
label-studio version(pip) or UI footer – expect 1.23.0- Signup/login loads on 8080, no 500
- Throwaway project + one tiny image or text file; if the labeling canvas opens, static files and storage are healthy
Docker logs: bind success, no PermissionError, no missing-module stack.
Common install errors and fixes
PermissionError: [Errno 13] on /label-studio/data/media – you skipped the chown. Fix ownership on mydata (GID 0 or 1001:0), rerun. Details above; same story on the troubleshoot page.
lxml / missing build deps (Windows pip) – clean venv, prebuilt wheel first, then pip install --ignore-installed label-studio.
Blank UI after a Docker bump – keep identical -v mounts, pull, recreate the container. Backup mydata before you delete the old container. Stale browser cache is boring and real.
Ever notice how the permission dance carries half of this tool’s “Docker is hard” reputation? Get GID right once; it stays right.
Upgrade and uninstall
Pip upgrade: same venv → pip install --upgrade label-studio → label-studio start. Backup projects/DB first. Read 1.23.0 notes if you build derivative images (Alpine is the break).
Docker upgrade:
docker stop label-studio
docker pull heartexlabs/label-studio:latest
docker rm label-studio
# identical -v mounts
docker run -it --name label-studio -p 8080:8080
-v "$(pwd)/mydata:/label-studio/data"
heartexlabs/label-studio:latest
Migrations usually run on start per the community upgrade guide. If logs complain, exec into the container and run migrate from the app dir.
Cleanup:
- Docker:
docker stop label-studio && docker rm label-studio; optionaldocker rmi heartexlabs/label-studio:latest; deletemydataonly when annotations can go - Pip: deactivate,
pip uninstall label-studio, remove the venv, drop any custom data dir
FAQ
Which install method should I pick for a small team?
Docker with a bind mount or named volume. Isolation beats “worked on my laptop” the day a second annotator joins.
Does 1.23.0 need a new database migration from 1.22?
Usually the app applies what it needs on start. Still back up mydata (or Postgres) before the pull. The 1.23.0 notes lean UI/Data Manager and Alpine more than schema drama – treat any major jump as backup-first anyway. Empty UI after upgrade? Confirm the volume path did not drift, then read migrate lines in the logs.
Can I run it fully offline?
Yes – offline is not the same as “never touched a registry.” On a networked box: docker pull heartexlabs/label-studio:latest && docker save heartexlabs/label-studio:latest | gzip > ls.tar.gz, copy the tarball, docker load, run with your volume. Pip wheels vendor the same way. People forget the pull/save step and then blame the app for needing net at runtime; the runtime itself is fine once the image or wheels are local.
Next: mkdir + chown :0 + docker run, open localhost:8080, create the first project. Wire storage or an ML backend after labels actually move.