Why Hoarder Might Be the Bookmark Manager You Actually Stick With
Browser bookmarks are a graveyard. You save something, forget it exists, and never find it again because your folder structure made sense three years ago and makes no sense now. Hoarder is a self-hosted bookmark manager built to fix exactly that problem – it gives you full-text search, automatic tagging via AI, link previews, and a clean interface that actually encourages you to use it. You run it on your own server, your data stays yours, and nothing disappears because a startup shut down.
Hoarder supports multiple users, has mobile apps for iOS and Android, and offers a browser extension for one-click saving. It can archive pages locally, extract readable article text, and use an optional AI model (via OpenAI or a local Ollama instance) to auto-tag bookmarks the moment they’re saved. For anyone who has tried and abandoned Pinboard, Raindrop, or Pocket, Hoarder is worth a serious look.
This guide walks through a complete Docker-based installation on a Linux server.

What You Need Before Starting
You need a Linux server – a VPS, a home server, or even a Raspberry Pi 4 with enough RAM. Hoarder’s stack includes the main app, a MeiliSearch instance for full-text search, and an optional Chrome instance for screenshot and article extraction. Together they’re light enough to run on a machine with 2GB of RAM, though 4GB gives you comfortable headroom, especially if you enable the browser-based archiving feature.
Docker and Docker Compose must be installed. If you’re also running a self-hosted RSS reader like Miniflux, you likely have both already. You’ll also want a domain or subdomain pointed at your server if you plan to access Hoarder from outside your local network, and a reverse proxy like Caddy or Nginx Proxy Manager to handle HTTPS. Finally, generate a few random strings in advance for environment secrets – you can use openssl rand -hex 32 for each one.
Port 3000 is Hoarder’s default internal port. You won’t expose it directly – your reverse proxy will sit in front of it. MeiliSearch runs on port 7700 internally. Neither needs to be publicly accessible on its own.
Setting Up the Docker Compose Stack
Create a directory for the project – something like /opt/hoarder – and inside it create a docker-compose.yml file. The stack has three services: hoarder-web, meilisearch, and optionally hoarder-chrome. The Chrome service is what enables screenshot capture and article text extraction. It’s optional in theory but worth including – without it, bookmarks are saved as plain links with no preview or archived content.

A working docker-compose.yml for Hoarder looks like this:
- meilisearch – uses the
getmeili/meilisearch:v1.6image, setsMEILI_NO_ANALYTICS=trueand aMEILI_MASTER_KEYenvironment variable, and mounts a volume for persistent index data. - hoarder-chrome – uses
gcr.io/zenika-hub/alpine-chrome:123with the command--no-sandbox --disable-gpu --remote-debugging-port=9222 --remote-debugging-address=0.0.0.0. No ports exposed externally. - hoarder-web – uses
ghcr.io/hoarder-app/hoarder:latest, depends on both other services, mounts a data volume, and takes several environment variables.
The environment variables for hoarder-web are where most of the configuration lives. Set NEXTAUTH_SECRET to a random 32-byte hex string. Set NEXTAUTH_URL to your full domain, including https://. Set MEILI_ADDR to http://meilisearch:7700 and MEILI_MASTER_KEY to the same key used in the MeiliSearch service. Set BROWSER_WEB_URL to http://hoarder-chrome:9222 if you’re including the Chrome service. If you want AI auto-tagging, add OPENAI_API_KEY with a valid key, or set OLLAMA_BASE_URL if you’re running a local model. The DATA_DIR variable should point to wherever your volume is mounted – typically /data inside the container.
Launching and Configuring Hoarder
Run docker compose up -d from your project directory. Docker will pull the images and start all three containers. Give it a minute, then check logs with docker compose logs -f hoarder-web to confirm the app started without errors. MeiliSearch takes a few seconds to initialize its indexes – if Hoarder logs show a connection retry at startup, that’s normal and resolves on its own.
Once running, point your reverse proxy at localhost:3000 and access your domain in a browser. You’ll be prompted to create an admin account on first launch. Do this immediately – Hoarder does not restrict registration by default, so anyone who reaches your URL can create an account unless you disable open registration in the settings after setup. Under Settings, you’ll find the option to turn off new user signups once your accounts are created. You’ll also find the API key section there, which you’ll need if you want to connect the mobile apps or browser extension.
The browser extension is available for Chrome and Firefox. After installing it, enter your Hoarder URL and API key – from that point, saving a bookmark is a single click. The extension sends the URL to your server, which triggers a background crawl: MeiliSearch indexes the page text, Chrome captures a screenshot, and if AI tagging is enabled, the content gets analyzed and tagged automatically within a few seconds. The result is a searchable, tagged, visually browsable archive of everything you’ve saved.

Keeping It Running
Set up a volume backup strategy before you accumulate bookmarks worth losing. The Hoarder data directory contains your database, cached screenshots, and archived article content – back it up with any tool that can copy files while containers are running, or stop the stack briefly with docker compose stop before snapshotting. Updates are straightforward: pull the new image with docker compose pull, then restart with docker compose up -d. Hoarder handles database migrations automatically on startup, so there’s no manual schema work between versions. The one thing that will catch you off guard: if you enable AI tagging on OpenAI and save bookmarks aggressively, API costs add up faster than expected – a local Ollama model sidesteps that entirely, though tagging quality depends on which model you run.





