Skip to content

Database

Parako.ID supports three database backends. Choose based on your deployment needs:

FeatureSQLiteMongoDBPostgreSQL
Setup complexityZero — file-basedModerateModerate
ORMPrismaMongoosePrisma
Multi-tenancyNot supportedMongoose tenant pluginRow-level security (RLS)
Clustering (PM2)Single instance onlyMultiple instancesMultiple instances
Best forDevelopment, small deploymentsProduction, multi-tenancyProduction, strict data integrity

Set the database via the STORAGE_ADAPTER environment variable in .env:

Terminal window
STORAGE_ADAPTER=sqlite # Default
STORAGE_ADAPTER=mongodb
STORAGE_ADAPTER=postgresql

SQLite requires no external database server. Data is stored in a single file.

Terminal window
STORAGE_ADAPTER=sqlite
STORAGE_SQLITE_PATH=./data/parako.db
Terminal window
# Generate Prisma client for SQLite
yarn db:generate
# Push schema to database (creates file if needed)
yarn db:push
# Open Prisma Studio to inspect data
yarn db:studio
  • Single process only — You must set PM2_INSTANCES=1 in production. SQLite does not support concurrent writes from multiple processes. The application enforces this at startup and refuses to start if violated.
  • No multi-tenancy — Multi-tenancy requires MongoDB or PostgreSQL.
  • WAL mode — Parako.ID enables Write-Ahead Logging (WAL) for better read concurrency.

For continuous SQLite backups, see SQLite Backup with Litestream.

MongoDB is the most battle-tested option, with full support for multi-tenancy via a global Mongoose tenant plugin.

Terminal window
STORAGE_ADAPTER=mongodb
STORAGE_MONGODB_URI=mongodb://localhost:27017/parako

No schema push is needed — Mongoose creates collections automatically on first use.

Terminal window
# Start the application
yarn dev

When MULTI_TENANCY_ENABLED=true, a global Mongoose plugin automatically scopes all queries by tenant_id. This provides transparent data isolation without changes to your query code.

Special tenants:

TenantPurpose
defaultUsed when no tenant is resolved
_opsInternal operations tenant
_platformsPlatform administration (SaaS control plane)

Parako.ID creates these MongoDB collections:

Application data:

  • users — User accounts and profiles
  • activities — Audit log entries
  • settings — Application configuration (versioned)
  • socialintegrations — Social login provider configurations
  • tenants — Tenant registry (not tenant-scoped)
  • jwks_keys — JWKS signing keys
  • tenant_settings_overrides — Per-tenant configuration overrides

OIDC adapter collections (created by node-oidc-provider, PascalCase names):

  • Session, Grant, Client, AccessToken, AuthorizationCode, RefreshToken, DeviceCode, ClientCredentials, InitialAccessToken, RegistrationAccessToken, Interaction, ReplayDetection, PushedAuthorizationRequest, BackchannelAuthenticationRequest

PostgreSQL uses Prisma as its ORM and supports row-level security (RLS) for multi-tenancy.

Terminal window
STORAGE_ADAPTER=postgresql
STORAGE_POSTGRESQL_URL=postgresql://user:password@localhost:5432/parako
Terminal window
# Generate Prisma client for PostgreSQL
yarn db:generate:pg
# Run migrations
yarn db:migrate
# Deploy migrations (production, no prompts)
yarn db:migrate:deploy
# Open Prisma Studio
yarn db:studio

Both PostgreSQL and SQLite use the same Prisma schema with these tables:

  • users — User accounts with MFA, WebAuthn, and recovery sub-tables
  • user_mfa, user_mfa_totp, user_mfa_email_otp — MFA configuration
  • user_webauthn_credentials — WebAuthn/FIDO2 passkeys
  • user_recovery, user_backup_codes, user_security_questions — Account recovery
  • user_notification_prefs — Notification preferences
  • activities, activity_actors, activity_targets, activity_devices — Audit log
  • settings — Application configuration (versioned)
  • social_integrations — Social login provider configurations
  • tenants — Tenant registry
  • tenant_settings_overrides — Per-tenant configuration overrides
  • jwks_keys — JWKS signing keys
  • sessions — Session store
  • oidc_store — OIDC tokens, grants, and interactions (single table for all OIDC models)

For production PostgreSQL with SSL:

Terminal window
STORAGE_POSTGRESQL_URL=postgresql://user:password@host:5432/parako?sslmode=require

PostgreSQL multi-tenancy uses a Prisma extension (src/db/extensions/tenant.extension.ts) that injects SET LOCAL app.tenant_id and automatically filters all queries by tenant_id. Row-level security (RLS) policies provide a belt-and-suspenders safety net at the database level. Each table includes a tenant_id column.

The OIDC storage adapter controls where tokens, sessions, grants, and other OIDC artifacts are persisted. By default, it uses the same backend as your primary database, but you can separate them.

Terminal window
# Use Redis for OIDC storage while keeping MongoDB for application data
STORAGE_ADAPTER=mongodb
OIDC_STORAGE_ADAPTER=redis

Available options:

AdapterStorage typeBest for
sqlitePersistent (file)Development
mongodbPersistentProduction
postgresqlPersistentProduction
redisEphemeral (in-memory)High-throughput, clustered deployments

When using Redis for OIDC storage, configure the Redis connection:

Terminal window
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your_redis_password
REDIS_DATABASE=0

Redis provides faster token lookups at the cost of data loss on restart. This is acceptable for OIDC tokens since clients can re-authenticate, but you should use a persistent store if session continuity across restarts is important.

Parako.ID abstracts database access through the repository pattern:

repositories/
├── interfaces/ # Database-agnostic contracts
│ ├── user.repository.interface.ts
│ ├── activity.repository.interface.ts
│ └── ...
├── mongoose/ # MongoDB implementations
│ ├── user.repository.ts
│ └── ...
└── prisma/ # SQLite/PostgreSQL implementations
├── user.repository.ts
└── ...

The application selects the correct repository implementation at startup based on STORAGE_ADAPTER. This means switching databases requires only changing the environment variable and running the appropriate setup commands — no application code changes.