Grimmory: a self-hosted library for ebooks, comics and audiobooks, run from Docker
A self-hosted library for your ebooks, comics, and audiobooks
At a glance
- What is it?
- Grimmory is an AGPL-3.0 Spring Boot and Angular application that serves EPUB, MOBI, CBZ, CBR, PDF and audiobook files from your own hardware. It installs with Docker Compose against MariaDB, and the trade-offs show up in format handling and in which clients can talk to it.
- Who is it for?
- Adopt Grimmory if you already run Docker Compose, want one server holding EPUBs, comics and audiobooks, and read through a browser or an OPDS client. Do not adopt it if you need a native iOS or Android app, or if your library lives on NFS or SMB storage, since DISK_TYPE=NETWORK disables file operations.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What Grimmory is for, and who ends up running it
Grimmory is a server you host yourself that turns a folder of files into a browsable library. The README describes it as "a self-hosted digital library for people who take their reading seriously", and the format table backs that up: EPUB, MOBI, AZW, AZW3 and FB2 for ebooks, PDF for documents, CBZ, CBR and CB7 for comics, and M4B, M4A, MP3 and OPUS for audiobooks. That spread is the point. Most self-hosted readers pick one lane, usually EPUB, and leave comics or audio to a second service.
The audience is narrower than the format list suggests. You need Docker and Docker Compose, a MariaDB instance, and a host that can hold your files. The docker-compose.yml in the repository mounts three paths: ./data for the application, ./books for the library, and ./bookdrop for the import folder. That is a server-shaped deployment. Someone who reads on one laptop and wants a local file manager is not the target.
The feature set leans toward collection management rather than pure reading. Smart Shelves are described as custom and dynamic shelves with rule-based filtering, tagging and full-text search. Metadata lookup pulls covers, descriptions, reviews and ratings from Google Books, Open Library and Amazon, and the README says all of it stays editable. Multi-user support separates shelves, progress and preferences per account, with local or OIDC authentication. If you are the only reader and you never tag anything, most of that machinery is idle.
How the pieces fit: Spring Boot, Angular, MariaDB and a watched folder
The repository layout answers the architecture question faster than the README does. There are two top-level directories, backend/ and frontend/, plus a root package.json that declares a pnpm workspace with [email protected] and Node >=24. The Dockerfile builds them in two stages. The first stage is node:24-alpine, which runs pnpm install --frozen-lockfile and then pnpm -C frontend run build:prod. The second stage is gradle:9.5.1-jdk25-alpine, which copies the compiled frontend into /tmp/frontend-dist and runs ./gradlew bootJar with -PfrontendDistDir pointing at it. The result is a single Spring Boot jar, and the frontend is static assets inside it.
Persistence is MariaDB, not SQLite. The .env sample sets DATABASE_URL=jdbc:mariadb://mariadb:3306/grimmory, and the compose file pins lscr.io/linuxserver/mariadb:11.4.5 with a mariadb-admin ping healthcheck every 5 seconds. The Grimmory service waits on that healthcheck through depends_on with condition: service_healthy, so startup order is enforced rather than hoped for.
The import path is BookDrop. The README says you drop files into a watched folder and Grimmory detects, enriches and queues them for import automatically. That maps to the ./bookdrop volume. Metadata enrichment happens after detection, which is why the metadata providers matter beyond cosmetics: a file with no embedded cover depends on those lookups to become findable.
One configuration flag changes the application's behaviour more than the rest. DISK_TYPE defaults to LOCAL, and the README states that NETWORK "disables file operations". That is a deliberate split: on network storage, Grimmory stops trying to move or rename files and presumably relies on the index instead. It is a sensible concession to NFS and SMB semantics, but it also means the feature set is not identical across storage backends.
Installing Grimmory with Docker Compose and reaching the first book
The README requires Docker and Docker Compose and points at the full documentation for OIDC and advanced configuration. Start with the .env file. These keys are copied from the sample, and the password values are the ones the README ships, so change them before the container is reachable from anywhere but localhost.
APP_USER_ID=1000
APP_GROUP_ID=1000
TZ=Etc/UTC
DATABASE_URL=jdbc:mariadb://mariadb:3306/grimmory
DB_USER=grimmory
DB_PASSWORD=ChangeMe_Grimmory_2025!
API_DOCS_ENABLED=false
DISK_TYPE=LOCAL
DB_USER_ID=1000
DB_GROUP_ID=1000
MYSQL_ROOT_PASSWORD=ChangeMe_MariaDBRoot_2025!
MYSQL_DATABASE=grimmoryThe compose file defines two services. The Grimmory container publishes port 6060 and mounts ./data, ./books and ./bookdrop. The healthcheck calls http://localhost:6060/api/v1/healthcheck with a 60 second interval and a 60 second start period, which tells you the first boot is expected to take a while.
services:
grimmory:
image: grimmory/grimmory:latest
ports:
- "6060:6060"
volumes:
- ./data:/app/data
- ./books:/books
- ./bookdrop:/bookdrop
depends_on:
mariadb:
condition: service_healthyBring it up and open the interface:
docker compose up -dThen visit http://localhost:6060, create the admin account, and create a library. The README adds a constraint that catches people out: all libraries must be created within directories mounted on the host, so the library root has to live under /books, not at an arbitrary path inside the container. Put a few EPUBs or CBZ files into ./books before you create the library, or into ./bookdrop if you want BookDrop to pick them up. Nightly builds come from the develop branch and are tagged nightly; stable images are published from semantic-release tags on main as vX.Y.Z plus latest.
Where Grimmory gets awkward: formats, storage and clients
The format table lists MOBI, AZW and AZW3 as supported ebooks, but the Dockerfile tells a more specific story. It builds a kepubify layer, with KEPUBIFY_VERSION 4.0.4 and an amd64 checksum, and a separate ffprobe layer from mwader/static-ffmpeg:8.1. Kepubify converts EPUB to Kobo's KEPUB format, and ffprobe inspects media files for the audiobook side. Those are the two formats that need real tooling. Everything else is largely a matter of parsing and serving.
The practical consequence is that the browser reader is documented for PDFs, EPUBs and comics. Audiobooks appear in the format list and the sync story mentions KOReader, but the README does not describe an in-browser audio player. If audiobooks are your main use, treat the browser experience as unverified and plan on a client.
The client situation is the harder limit. Device sync is described as connecting a Kobo, using any OPDS-compatible app, or syncing progress with KOReader. That is the whole list. Nothing in the README mentions a native iOS or Android application, and the related searches show people asking about both. If your reading happens on a phone with a vendor app and no OPDS support, Grimmory can hold the files but cannot reach that device.
Storage is the third constraint. DISK_TYPE=NETWORK disables file operations, so a NAS-backed library loses whatever those operations cover. The README does not enumerate them, which is itself a gap: you cannot tell from the documentation how much of the import and organize workflow survives on network storage. Test the specific workflow you care about before moving a large library onto a share.
Operationally, the stack is heavier than a single-binary reader. You are running Java, MariaDB, and a container that expects a 60 second healthcheck window. Heap dumps are off by default; the README shows how to enable them with JDK_JAVA_OPTIONS=-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/app/data and warns that the resulting .hprof files can be large and contain sensitive application data. That warning is worth taking literally on a shared host.
Grimmory and Calibre: two different answers to the same problem
The obvious comparison is Calibre. Calibre is a desktop application with a content server bolted on; its library is a directory structure the application manages, and metadata editing happens on the machine running it. Grimmory is a server application whose metadata lives in MariaDB and whose files live in a mounted folder. The difference shows up in multi-user behaviour: Grimmory separates shelves, progress and preferences per user with local or OIDC authentication, while Calibre's model assumes one operator at a keyboard. It also shows up in deployment: Calibre does not need a database, and Grimmory does not run without one.
The closer comparison is Audiobookshelf, which the related searches pair with Grimmory. Audiobookshelf starts from audio and treats ebooks as an addition. Grimmory starts from ebooks and comics and lists audiobook formats alongside them. If your collection is mostly M4B files, the audio-first tool is the better fit. If it is mostly EPUB and CBZ with a few audiobooks, Grimmory's ordering matches the collection.
The repository also mentions BookLore in the surrounding search data. Both are self-hosted library servers, and the meaningful difference to check is not the feature table but the storage model and the client list, since those are what you live with after the novelty wears off.
Licence, upgrades and what maintenance actually costs
Grimmory is AGPL-3.0. The practical implication for a self-hoster is that running it for yourself changes nothing about your obligations. The licence matters if you modify Grimmory and expose it to other people over a network: the AGPL's source-availability condition attaches to network use, unlike the GPL. The repository also carries a NOTICE file, and the Dockerfile copies both LICENSE and NOTICE into the build. If you intend to redistribute a modified image, read those files rather than a summary. This is a description of the licence, not legal advice.
The upgrade path is container replacement. Stable images are published from semantic-release tags on main as vX.Y.Z plus latest, and nightly images are built from develop and tagged nightly. The README points at https://grimmory.org/docs/getting-started for upgrade guides, which is where schema migrations would be described. The README itself does not document rollback, so the safe assumption is that you should take a MariaDB dump before pulling a new tag. The compose file keeps MariaDB state in ./mariadb/config, which makes that easy to snapshot.
Maintenance activity is visible: the last push to the develop branch was on 2026-09-10, and the most recent release listed is v3.3.3 on 2026-08-22. The repository is not archived. That tells you the project is moving, not that any particular version is stable for your workload. Running latest means accepting whatever the newest tag contains; pinning to a vX.Y.Z tag is the alternative the README explicitly supports in the compose comments.
The ongoing cost is the database. You are now responsible for MariaDB backups, disk growth and version upgrades on top of the application itself. That is the real price of the multi-user and metadata features, and it is the part people underestimate when they compare Grimmory to a desktop reader.
Editorial conclusion
Adopt Grimmory if you already run Docker Compose, want one server holding EPUBs, comics and audiobooks, and read through a browser or an OPDS client. Do not adopt it if you need a native iOS or Android app, or if your library lives on NFS or SMB storage, since DISK_TYPE=NETWORK disables file operations. Before committing, verify that the /books mount sits on local disk with enough room, that MariaDB 11.4.5 is a version you are willing to operate, and that your reading device speaks OPDS or is a Kobo, because the README lists no other sync path.
Frequently asked questions
Is Grimmory self-hosted?
Yes. Grimmory is a self-hosted digital library that you run yourself, typically with Docker Compose and a MariaDB container. The README requires Docker and Docker Compose and mounts your own ./books directory into the application.
How do I install Grimmory?
Create a .env file with the application, database and MariaDB values, write a docker-compose.yml using the grimmory/grimmory:latest image, then run docker compose up -d. Open http://localhost:6060 to create the admin account and build your first library.
What is Grimmory?
Grimmory is a self-hosted library for ebooks, comics and audiobooks. It supports EPUB, MOBI, AZW, AZW3, FB2, PDF, CBZ, CBR, CB7, M4B, M4A, MP3 and OPUS, and includes a browser reader, metadata lookup and OPDS access.
What is the best library ebook app?
That depends on where your files live and what you read on. Grimmory keeps EPUBs, comics and audiobooks on your own server and reaches them through a browser, a Kobo, an OPDS app or KOReader, while a desktop tool such as Calibre keeps the library on the machine running it and needs no database.
What is an ebook library?
In Grimmory's case it is a directory mounted on the host that the application indexes and serves. The README states that all libraries must be created within directories mounted on the host, such as the /books/ directory in the sample docker-compose.yml.
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/grimmory-tools-grimmory)