Every household has the drawer. Tax letters, warranty cards, the lease, a pay stub from three jobs ago, the vet's invoice you'll need exactly once. It all goes in the drawer, and finding anything means digging through all of it.
Paperless-ngx replaces the drawer. Scan a document, or drop in a PDF, and it reads the text with OCR, figures out who sent it and what it is, tags it, and files it into a searchable archive on your own server. It's one of the most popular self-hosted apps there is, with around 45,000 stars on GitHub, and once it's running it quietly changes how you deal with paper.
Where it came from
Paperless-ngx is the third generation of the idea. The original Paperless was followed by Paperless-ng, a rewrite with a modern interface. When that project's single maintainer stepped back, the community forked it as Paperless-ngx so that a team would carry it forward instead of one person. It's GPL-3.0 licensed, built on Django and Angular, and on the 3.x release line.
What it does
- OCR on everything. It uses the open-source Tesseract engine to read more than 100 languages, adding searchable, selectable text even to image-only scans.
- Archival PDFs. Each document is stored as a PDF/A, the format built for long-term storage, next to the untouched original.
- Automatic filing. A machine-learning classifier trained on your own documents suggests and assigns tags, correspondents and document types.
- Full-text search with autocomplete, relevance ranking, highlighted matches and "more like this".
- Many file types. PDFs, images and plain text work out of the box. Word, Excel, PowerPoint and LibreOffice files work with an optional add-on.
- Email import. It watches mail accounts and pulls in attachments according to rules you define.
- Workflows that assign metadata, send emails, call webhooks and more, based on triggers.
- Multiple users with global and per-document permissions, two-factor login, and share links that can expire.
- Your files stay plain. Documents are ordinary files on disk, in a folder layout you control. Nothing is locked inside a database.
The four things every document has
Paperless doesn't use folders. Everything is organized with four kinds of metadata, and understanding them is the key to the whole app:
CORRESPONDENT who it's from or to Electric Co, IRS, Dr. Patel
DOCUMENT TYPE what kind of thing it is invoice, contract, statement
TAGS any labels you like taxes-2026, car, paid, inbox
STORAGE PATH where the file lands {{ correspondent }}/{{ created_year }}/{{ title }}
Tags are the clever part. A document can carry many tags, so "car insurance renewal" can live under car, insurance and taxes-2026 at the same time. A folder can't do that. Add custom fields (amounts, due dates, policy numbers) and an archive serial number that matches the label on the physical copy in your binder, and you can find anything, digital or paper.
Install it with Docker
The quickest route is the official install script. It asks a few questions, writes the compose files, starts the containers and creates your admin account:
bash -c "$(curl --location --silent --show-error \
https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)"
If you prefer to see every piece, set it up by hand. The project ships compose files for SQLite, PostgreSQL and MariaDB, each with an optional -tika variant that adds Office document and email support. PostgreSQL is the recommended choice for new installs. Trimmed down, the Postgres version looks like this:
services:
broker:
image: docker.io/valkey/valkey:9-alpine
restart: unless-stopped
volumes:
- redisdata:/data
db:
image: docker.io/library/postgres:18
restart: unless-stopped
volumes:
- pgdata:/var/lib/postgresql
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: paperless
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:latest
restart: unless-stopped
depends_on: [db, broker]
ports:
- "8000:8000"
volumes:
- data:/usr/src/paperless/data
- media:/usr/src/paperless/media
- ./export:/usr/src/paperless/export
- ./consume:/usr/src/paperless/consume
env_file: docker-compose.env
environment:
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
PAPERLESS_DBENGINE: postgresql
volumes:
data:
media:
pgdata:
redisdata:
Grab the matching docker-compose.env and .env from the repo's docker/compose folder, then set at least these in docker-compose.env:
# Required. Generate one with:
# python3 -c "import secrets; print(secrets.token_urlsafe(64))"
PAPERLESS_SECRET_KEY=change-me
PAPERLESS_TIME_ZONE=America/New_York
PAPERLESS_OCR_LANGUAGE=eng
# Your host user's IDs (run: id -u / id -g), so you can
# write into the consume folder
USERMAP_UID=1000
USERMAP_GID=1000
# Only if you'll reach it from a domain
#PAPERLESS_URL=https://paperless.example.com
Then:
docker compose pull
docker compose up -d
# open http://localhost:8000 and create your superuser
Getting paper in
There are four doors into Paperless, and most setups end up using all of them:
- The consume folder. Anything dropped into
./consumeis picked up, processed and moved into the archive. Point your scanner's "scan to network folder" at it through a Samba share or FTP, and scanning becomes a one-button job. (The file leaves the consume folder once it's processed. That's expected.) - Drag and drop. Drop a file anywhere in the web interface.
- Email. Add an IMAP account under Settings → Mail, then write rules: which folder to watch, which attachments to take, which tags to apply, and what to do with the message afterwards.
- Phone. Community mobile apps scan and upload straight from your camera. The project wiki keeps a list of them.
Tip: if your consume folder lives on an NFS share, set PAPERLESS_CONSUMER_POLLING_INTERVAL. Network file systems don't send the change notifications Paperless listens for, so without polling, new files just sit there.
Let it file things for you
This is where Paperless earns its keep. Every tag, correspondent, document type and storage path has a matching rule that runs against each new document's text:
Any any of the words appear "electric power"
All every word appears, any order "invoice 2026"
Exact the exact phrase appears "Bank of America"
Regex a regular expression Policy\s+No\.\s*\d+
Fuzzy close-enough partial match Hydro Quebec
Auto learn from how you've filed things before
Auto is the default, and it gets good fast. File your first few dozen documents by hand and the classifier learns your habits. A new statement from your bank arrives already tagged, typed and assigned. Use the explicit rules for the cases where you want certainty, such as "anything containing my policy number goes under insurance".
Workflows
Workflows go a step further: when this happens, do that. Triggers include a document starting to be consumed, being added, being updated, or a scheduled date. Actions include assigning or removing metadata, sending an email, calling a webhook, removing a PDF password, or moving a document to the trash. Some real-world uses:
- Everything that arrives by email from your accountant gets the
taxestag and is shared with your partner's account. - Warranty documents trigger a scheduled reminder email 30 days before a custom "warranty ends" date field.
- Bank statements, which always come password-protected, get the password stripped on arrival so they can be OCR'd and searched.
- A webhook pings your home-automation system whenever a new invoice lands.
Barcodes and ASNs
For heavy paper users: Paperless reads barcodes on PDF pages. Print a sheet of ASN barcode stickers, put one on each paper document before scanning, and the archive serial number is set automatically. To find the original later, read the ASN off the screen and pull that number from your binder. Barcode pages can also split a big batch scan into separate documents.
The optional AI features
Recent versions add opt-in AI features on top of the classic classifier: LLM-written suggestions for titles, dates and tags, chatting with a single document or your whole archive, and similar-document search. They're off by default and work with a local model through Ollama or any OpenAI-compatible API.
Think before you switch them on. With a remote provider, your document text leaves your server, and that defeats much of the point of self-hosting tax returns and medical letters. If you want these features, a local model keeps everything at home.
Backups, and one big warning
The project says it plainly: Paperless stores your documents unencrypted, and you should never run it on an untrusted host. Run it on your own hardware or a server you control, keep it off the open internet (use a VPN like WireGuard or Tailscale to reach it from outside), and back it up.
For backups, use the built-in exporter. It writes every document plus all metadata into a folder that can be re-imported into a fresh install:
docker compose exec -T webserver document_exporter ../export
Put that on a nightly cron job and copy the export folder off the machine with your usual backup tool. A document archive with no off-site backup is just a fancier drawer that can burn down.
Running it on small hardware
Paperless runs fine on a Raspberry Pi 4 or a cheap mini PC. On low-power machines:
- Use SQLite instead of Postgres to save memory.
- Set
PAPERLESS_OCR_PAGES=1. The first page is usually enough to find a document. - Lower
PAPERLESS_TASK_WORKERSandPAPERLESS_THREADS_PER_WORKER, so a big batch doesn't freeze the machine. - Set
PAPERLESS_WEBSERVER_WORKERS=1. - Let your scanner do the OCR if it can, and leave
PAPERLESS_OCR_MODEonauto.
Tips from the trenches
- Use an inbox tag. New documents get the
inboxtag automatically. Review the inbox once a week, fix anything mis-filed, and remove the tag. Every correction trains the classifier. - Start with the backlog in batches. Scanning ten years of paper in one go is overwhelming. Do a box a weekend.
- Keep the paper you're legally required to keep. A scan isn't always a legal substitute. Put an ASN on those originals and keep them in a binder in number order.
- Try the demo first. There's a public demo at demo.paperless-ngx.com (login
demo/demo). It resets often, so don't upload anything real.
Paperless-ngx or Mayan EDMS?
The other big name in self-hosted document management is Mayan EDMS, which gets its own transmission today. The short version: Paperless-ngx is built for a household or small office that wants paper to vanish into a searchable archive with as little effort as possible. Mayan is built for organizations that need formal document types, approval workflows, version control and fine-grained access control, and it asks for more setup and more server in return. For most homelabs, Paperless is the right first stop.
Verdict
Paperless-ngx is the rare self-hosted app that pays you back in time every week. The setup is a compose file. The first weekend of scanning is a chore. After that, paper stops being a problem: it goes in the scanner, comes out tagged and searchable, and the drawer gets recycled.
Start with the GitHub repo and the documentation, which is excellent. Links are also in the downloads directory and the resource index.
End of transmission.