Set up PostgreSQL
localmail stores every message, label, and piece of metadata in a PostgreSQL database. Before you install localmail, you need a running Postgres instance and a dedicated database for it.
What you need
- PostgreSQL 14 or newer. 16 is recommended.
- The
pgvectorextension. localmail uses it for the vector search index. Postgres 14+ supports it via the standard extension mechanism. - Roughly 1.5× the on-disk size of your raw mail. IMAP servers store RFC822 bytes; localmail keeps those plus parsed columns and search indexes.
Skip ahead to Create the database and role.
You only need to install the pgvector extension and create
one fresh database — there is no need to re-install Postgres itself.
Install PostgreSQL
macOS — Postgres.app (easiest)
- Download Postgres.app and drag
it to
/Applications. - Open it, click Initialize to create a default cluster.
- Add the CLI tools to your
PATH:
Open a new terminal so the change takes effect.sudo mkdir -p /etc/paths.d echo /Applications/Postgres.app/Contents/Versions/latest/bin \ | sudo tee /etc/paths.d/postgresapp - Verify:
psql --version psql -l # lists databases
macOS — Homebrew
brew install postgresql@16 pgvector
brew services start postgresql@16
Linux — Debian / Ubuntu
sudo apt update
sudo apt install postgresql postgresql-contrib postgresql-16-pgvector
sudo systemctl enable --now postgresql
Older releases (Ubuntu 22.04 and earlier) may not have a
postgresql-16-pgvector package. Use the
PostgreSQL APT
repository to pull a current version, or build pgvector from source
(see below).
Linux — Fedora / RHEL
sudo dnf install postgresql-server postgresql-contrib pgvector
sudo postgresql-setup --initdb
sudo systemctl enable --now postgresql
Docker (any OS)
If you would rather not install Postgres on your host, use the official
pgvector image. The example below matches the DSN in
config.example.toml exactly, so you can copy-paste through
the rest of the manual:
docker run -d \
--name localmail-postgres \
--restart unless-stopped \
-e POSTGRES_USER=localmail \
-e POSTGRES_PASSWORD='local@@mail' \
-e POSTGRES_DB=localmail \
-p 5532:5432 \
-v localmail-pgdata:/var/lib/postgresql/data \
pgvector/pgvector:pg16
The container exposes Postgres on host port 5532
(note the non-standard port to avoid clashing with a local install).
Data persists in the localmail-pgdata volume.
If you used the Docker recipe above, the localmail
database, the localmail role, and the password are already
set up — you can skip the rest of this page and jump to
Step 2 — Install localmail. You still need
to run CREATE EXTENSION vector; once, which the next-step
localmail init-db will trigger via migrations.
Create the database and role
You will create a dedicated Postgres role and database so localmail's credentials never overlap with anything else on your system.
-
Open a superuser
psqlsession.On macOS with Postgres.app or Homebrew the current Unix user is already a superuser:
psql postgresOn Linux with the system Postgres package, switch to the
postgresuser first:sudo -u postgres psql -
Create the role and database.
Pick a strong password and remember it — you will put it in
config.tomlin Step 2. The example useslocal@@mail(matchesconfig.example.toml); replace it with your own.CREATE ROLE localmail WITH LOGIN PASSWORD 'local@@mail'; CREATE DATABASE localmail OWNER localmail; \q -
Enable the
pgvectorextension.Connect to the newly-created database as a superuser (extensions can only be enabled by superusers) and create the extension:
psql -d localmail -- or: sudo -u postgres psql -d localmail CREATE EXTENSION IF NOT EXISTS vector; \qIf you get
could not open extension control file ... vector.control, thepgvectorpackage is missing. Re-check the install commands above for your platform. -
Verify the credentials work.
Open a new shell and connect as the
localmailrole:psql 'postgresql://localmail:local%40%40mail@localhost:5432/localmail'(If you used the Docker recipe, port is
5532not5432.) You should land at alocalmail=>prompt with no errors. \q to quit.URL-encode special charsThe
@in a password must appear in the DSN as%40; an unescaped@would be parsed as the host separator. Other characters that need encoding::→%3A,/→%2F,→%20.
What about backups?
Now is a good moment to plan backups, even though there is nothing in the database yet. localmail's archive is the only copy of any mail you sync after you delete the original from the IMAP server, so a backup strategy matters. Two simple options:
- Daily
pg_dumppiped to your normal backup tool (Time Machine, Backblaze, restic, …):pg_dump -Fc -d localmail -f localmail-$(date +%F).dump - Filesystem-level backup of the Postgres data
directory plus the
~/localmail/attachments tree. Stop the daemon and Postgres before the snapshot to ensure consistency.
Troubleshooting
| Symptom | Fix |
|---|---|
connection refused on psql |
Postgres isn't running. brew services start
postgresql@16 / sudo systemctl start postgresql
/ docker start localmail-postgres. |
FATAL: password authentication failed |
You typed the password wrong, or the host's
pg_hba.conf requires peer authentication.
On Linux, edit /etc/postgresql/16/main/pg_hba.conf,
change the local rule from peer to
md5, then sudo systemctl reload
postgresql. |
extension "vector" is not available |
The pgvector package is missing or not in the same
installation as the running server. Install it for the matching
major version (e.g. postgresql-16-pgvector for PG 16),
then restart Postgres. |