PostgreSQL setup
Using Docker (recommended)
The easiest way to run PostgreSQL is with the included Docker Compose setup:- PostgreSQL (port 5432) with the
groonga/pgroonga:latest-alpine-16image - Redis (port 6379)
- Elasticsearch (port 9200)
- Kibana (port 5602)
groonga/pgroonga image includes the pgroonga extension for full-text search support.
Manual installation
For bare-metal installations:- Install PostgreSQL 16+
- Create a database:
- Update
DATABASE_URLin.env:
Database schema
The schema is defined in TypeScript using Drizzle ORM inpackages/db/src/schema/:
- general.ts — Application tables (books, libraries, collections, etc.)
- auth.ts — better-auth tables (users, sessions, organizations, etc.)
- index.ts — Schema exports
Key tables
book
Core book records:(library_id, filehash) — prevents duplicate files within a library.
book_metadata
Extracted and enriched metadata:library & library_path
Libraries organize books and map to filesystem paths:(library_id, path) — one library cannot have duplicate paths.
scanned_file
Tracks which files have been scanned:(path, library_path_id) — tracks each file per library path.
Migrations
Nanahoshi uses Drizzle Kit for generating and running SQL migrations.Automatic migrations (production)
Migrations run automatically on server startup viarunMigrations() in packages/db/src/migrate.ts:
apps/server/src/index.ts before starting the HTTP server.
Manual migration workflow (development)
-
Modify the schema in
packages/db/src/schema/ - Generate a migration:
packages/db/src/migrations/ with auto-generated DDL statements.
- Review the migration file to ensure correctness
- Apply migrations:
Migration commands
From the repository root:packages/db/:
Drizzle configuration
Configuration is defined inpackages/db/drizzle.config.ts:
DATABASE_URL from apps/server/.env.
pgroonga extension
Thegroonga/pgroonga Docker image includes the pgroonga extension for full-text search. This is not currently used in the schema but is available for future use.
To enable:
Connection pooling
Drizzle uses thepg driver with a connection pool:
PGPOOLSIZE in your environment.
Seeding
The server runsfirstSeed() on startup (after migrations) to create initial data:
- Default admin user (if no users exist)
- Default organization
- System settings
packages/db/src/seed/seed.ts.
Backups
Docker volumes
For Docker deployments, back up thepostgres_data volume:
pg_dump
For bare-metal installations:Troubleshooting
Migration fails with “already exists”
If migrations are out of sync:- Check the
drizzle.__drizzle_migrationstable:
- Manually mark migrations as applied (if safe):
- Or reset and re-apply: