# Paperless-ngx: a searchable archive that stores your documents in clear text

> Paperless-ngx is the successor to Paperless and Paperless-ng, and the two things a reader needs before anything else are the project's own warning that data is stored unencrypted, and the fact that the install path is a Compose file or a curl script rather than a package you inspect first.

**paperless-ngx/paperless-ngx** — A community-supported supercharged document management system: scan, index and archive all your documents

- Repository: https://github.com/paperless-ngx/paperless-ngx
- Website: http://docs.paperless-ngx.com/
- Stars: 46,157 · Forks: 3,194
- Language: Python
- License: GPL-3.0
- Published: 2026-08-04 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/paperless-ngx-paperless-ngx

## The Important Note says clear text, no encryption, and a server in your own home

The last section of the README is a warning, and it is the most important paragraph in the file. Document scanners are typically used on the most sensitive paperwork a household owns, social insurance numbers, tax records and invoices. Paperless-ngx should never be run on an untrusted host, because information is stored in clear text without encryption. No guarantees are made regarding security, the project adds, though it says it tries, and the app is used at your own risk.

The recommended deployment follows from that: a local server in your own home with backups in place. That is a narrow instruction, and it rules out the deployments a reader might otherwise try first. A shared VPS, a cloud instance you do not administer alone, or a NAS exposed to the internet all move the archive somewhere other people can reach.

The consequence is that encryption is your problem to solve. The application stores documents in a form you can read without a key, so protecting them means filesystem or disk encryption, a network you control, and backups that are themselves protected. The security note is honest about the limits, which is more useful than a vague assurance, but it leaves the reader with a checklist rather than a mechanism.

## Two install paths, and the Compose files pull from the GitHub container registry

The easiest deployment is named first: `docker compose`. The files in the repository's `/docker/compose` directory are already configured to pull the image from the GitHub container registry, so this is a configuration you inherit rather than write. For readers who want to start immediately, the project also ships an install script that is run in one line:

```bash
bash -c "$(curl -L https://raw.githubusercontent.com/paperless-ngx/paperless-ngx/main/install-paperless-ngx.sh)"
```

That is a pipe from curl into bash, fetched from the `main` branch, and it is the shortest route offered. It is also the one where you are trusting a moving branch rather than a tag. Step by step guides for alternative installation methods live in the documentation at docs.paperless-ngx.com under setup and installation, which is where a reader who wants to know what the script does before running it should go.

The consequence is a split between convenience and inspection. The Compose path is auditable because you can read the files first, while the script path is convenient and opaque in equal measure.

## The demo runs on DigitalOcean with its credentials printed in the README

A hosted demo is available at demo.paperless-ngx.com, supported by DigitalOcean, and the login is printed in the file itself as `demo` / `demo`. The same sentence carries the caveat: demo content is reset frequently and confidential information should not be uploaded.

That is a sensible arrangement and a useful one for evaluation, because you can see the interface, the document list and the search before committing a server to it. It is also a shared instance, which puts it in tension with the Important Note at the end of the same file. The note is about how the software stores data, not about who may log in, and the demo is the one place in the project where anyone at all can log in.

The consequence for a reader is to treat the demo as a way to evaluate the interface and nothing more. It cannot show you how search performs against your own archive, it resets whatever you upload, and if you are tempted to load a real document to test OCR behaviour on it, the file says not to. The default branch here is `dev` rather than `main`, so a reader following links from the repository lands on development code, while the release list shows 3.2.1 published on 2026-09-20 and 3.2.0 the day before.

## Migrating from Paperless-ng is described as dropping in the new image

The migration story is one sentence: migrating from Paperless-ng is easy, just drop in the new docker image. The detail lives in the documentation, under setup and migrating to Paperless-ngx.

The claim is credible because the archive is a database plus a media volume rather than a bespoke format, so a newer image pointed at existing volumes can read them. It is still a one-sentence claim, and the parts that matter for a migration are the ones the sentence does not cover: whether your database needs migrating separately from the media, which version you can roll back to if the new image misreads something, and where your original documents sit in the meantime.

The consequence for a reader is that the sentence tells you the shape of the operation and not its cost. Treat it as a prompt to read the migration page and take a backup you have verified, because there is no rollback instruction in the README. It also explains why the project describes itself as the official successor to both the original Paperless and Paperless-ng, and why it says it was designed to distribute the responsibility of advancing and supporting the project among a team of people.

## The image is built in a Node stage and supervised by a pinned s6-overlay

The Dockerfile is a multi-stage build, and the first stage has nothing to do with Python. It starts from `docker.io/node:24-trixie-slim`, copies in `src-ui`, enables corepack and runs `pnpm install`, then builds the frontend with `./node_modules/.bin/ng build --configuration production`. A build argument named `PNGX_TAG_VERSION` rewrites a version string inside the environment file when the tag is a dev, beta, fix or feature build, so a pre-release image reports itself correctly.

The second stage switches to Python entirely, from `ghcr.io/astral-sh/uv:0.12.20-python3.14-trixie-slim`, and installs s6-overlay with the version locked at 3.2.2.0. Three environment settings govern its behaviour: `S6_BEHAVIOUR_IF_STAGE2_FAILS=2`, `S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0` and `S6_VERBOSITY=1`, with `/command` prepended to `PATH`. A case statement maps the build platform onto the s6 architecture names, so `amd64` becomes `x86_64` and `arm64` is handled alongside it.

The consequence for an operator is that supervision is s6 inside the container, not a restart policy outside it, and that a container start order question is answered by s6 settings rather than by Docker. The two pinned base images are also the versions to watch when a rebuild starts failing.

## The dependency list is a whole application server, and django's own version is not a guarantee

The Python package declares `requires-python = ">=3.11"` and carries classifiers for 3.11 through 3.15, and the runtime dependency list is not a small library's worth of entries. It includes `celery[redis]`, `channels` and `channels-redis`, `djangorestframework`, `drf-spectacular` for the schema, `django-allauth[mfa,socialaccount]`, `django-auditlog`, `django-guardian`, `django-soft-delete`, `django-treenode`, `imap-tools`, `filelock`, `gotenberg-client` for PDF handling, `llama-index-core` and `llama-index-embeddings-huggingface`, and `azure-ai-documentintelligence`.

Two comments in the file explain the shape of that list. One sits above the django pin and says django does not use semver, so only patch versions are guaranteed not to introduce breaking changes, which is why the constraint reads `django~=5.2.13`. The other is a TODO saying that moving certain things into groups would allow testing to not install a webserver, mysql and so on, which tells you that a test run currently pulls production dependencies with it.

The consequence is that there is no lightweight install here. A developer setting up the project to run one test also installs a web server stack, a broker and an embedding runtime, and the AI dependencies are present whether or not you use them.

## Work is split across three systems: Discussions for features, issues for bugs, Crowdin for text

The contributing section routes three kinds of work to three different places. Small changes are described as always welcome: bug fixes, enhancements and visual fixes. Anything bigger is supposed to start as a discussion first, and the documentation carries a development page for getting started. Ongoing contributors are pointed at the project's teams on GitHub, with frontend and ci/cd named as examples, plus a Matrix room.

Feature requests have their own home in GitHub Discussions, in a feature requests category, where you search for an existing idea, add your own and vote for the ones you care about. Bugs go to the issue tracker, with discussions offered for questions. Translations are coordinated on Crowdin at crowdin.com/project/paperless-ngx, and CONTRIBUTING.md has a section on translating Paperless-ngx.

The consequence is that where you file decides what you get. A one line fix arrives as a pull request, a behaviour change arrives as a discussion that may or may not become work, and a translation is never a pull request at all. A reader planning a feature should check the Discussions category first, because a vote count there is the closest thing the project offers to a roadmap.

## Two type checker baselines sit in the tree, which tells you the type debt is tracked, not fixed

The top level of the repository shows how the project is policed. `.pre-commit-config.yaml` is the commit gate, `.hadolint.yml` covers the Dockerfiles, `.prettierrc.js` and `.yamlfmt` cover formatting, and `.codecov.yml` covers coverage. Two more files are the interesting ones: `.mypy-baseline.txt` and `.pyrefly-baseline.json`.

A baseline file is a record of the errors a checker already reports, kept so that a new error is the only thing that fails. Having two of them, for two different checkers, tells you the project is not starting from a clean type check and has chosen to track the debt rather than pay it down. A contributor who adds code that produces a new diagnostic either fixes it or extends the baseline, and the second option is a decision someone has to notice.

The rest of the layout follows the same pattern of small, deliberate choices. `install-paperless-ngx.sh` and `paperless.conf.example` sit next to `uv.lock` and `zensical.toml` for documentation, `src/` and `src-ui/` are the backend and frontend, and `docker/`, `scripts/`, `docs/` and `.devcontainer/` hold the rest, with `CODEOWNERS` and `SECURITY.md` at the top.

## Conclusion

Paperless-ngx fits someone with a home server, a scanner and a vault of paperwork they want searchable, and it fits that person better than a hosted document service because the archive stays under their own roof. It is a poor fit for shared or multi-tenant hosting, and the project says so rather than leaving you to infer it. Before you deploy, read the Important Note in full, decide where the database volume and the media volume live, and confirm the backups the note assumes are actually running, because clear text storage plus a single disk is a data loss story rather than a security one.

## FAQ

### What is Paperless-ngx for?

It transforms physical documents into a searchable online archive, so scanned paper becomes something you can find and read from a browser. The package description puts it as a community supported document management system: scan, index and archive all your physical documents.

### Is Paperless-ngx secure?

The README says it should never be run on an untrusted host, because information is stored in clear text without encryption, and that no guarantees are made regarding security. It says the safest way to run it is on a local server in your own home with backups in place.

### How do I install Paperless-ngx?

The easiest route is `docker compose`, using the files in the repository's docker/compose directory, which are configured to pull the image from the GitHub container registry. A one line alternative runs the project's install script, and step by step guides for other methods are in the documentation at docs.paperless-ngx.com.

### Is Paperless-ngx any good?

It is the official successor to the original Paperless and Paperless-ng projects, licensed GPL-3.0, and the checked in version is 3.2.1 with 3.2.1 released on 2026-09-20. The project says it was designed to distribute the work of advancing and supporting it among a team, with teams for areas such as frontend and ci/cd.

### How do I install Paperless-ngx on a NAS?

The README does not describe NAS platforms specifically. It documents the Compose route, whose files pull the image from the GitHub container registry, and the install script, and it points to the setup section of the documentation for alternative installation methods.

## Sources

- [Official documentation](http://docs.paperless-ngx.com/)
- [Official README](https://github.com/paperless-ngx/paperless-ngx#readme)
- [Project repository](https://github.com/paperless-ngx/paperless-ngx)
- [Release notes](https://github.com/paperless-ngx/paperless-ngx/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/paperless-ngx-paperless-ngx
