Files
documenso/apps/docs/content/docs/self-hosting/configuration/database.mdx
T
ephraimduncan 138d663c25 chore: merge main, resolve biome formatting conflicts
Merge origin/main into feat/external-2fa-codes. Resolve formatting
conflicts caused by biome rollout; preserve both feature streams:
PR's external 2FA token + signing-session 2FA proof additions plus
main's RateLimit/RecipientExpired/signingReminders/date-auto-insert.

In complete-document-with-token.ts, drop the duplicate early
field-fetching block introduced when main moved that logic later
with date auto-insert support; keep the EXTERNAL_TWO_FACTOR_AUTH
check using derivedRecipientActionAuth.
2026-05-12 11:46:11 +00:00

491 lines
16 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Database Configuration
description: Configure PostgreSQL connection strings, pooling, SSL, migrations, and performance tuning for your Documenso deployment.
---
import { Accordion, Accordions } from 'fumadocs-ui/components/accordion';
import { Callout } from 'fumadocs-ui/components/callout';
import { Tab, Tabs } from 'fumadocs-ui/components/tabs';
## Supported Databases
Documenso requires **PostgreSQL 14 or later**. No other databases are supported.
PostgreSQL provides the reliability, performance, and feature set required for document signing workflows, including:
- ACID compliance for transaction integrity
- JSON support for flexible metadata storage
- Full-text search capabilities
- Robust backup and replication options
## Connection String Format
PostgreSQL connection strings follow this format:
```
postgresql://[user]:[password]@[host]:[port]/[database]?[parameters]
```
### Components
| Component | Description | Example |
| ------------ | ------------------------------- | ----------------- |
| `user` | Database username | `documenso` |
| `password` | Database password (URL-encoded) | `secretpass` |
| `host` | Database server hostname or IP | `localhost` |
| `port` | Database port | `5432` |
| `database` | Database name | `documenso` |
| `parameters` | Additional connection options | `sslmode=require` |
### Examples
**Local development:**
```
postgresql://documenso:password@localhost:5432/documenso
```
**Remote server with SSL:**
```
postgresql://documenso:password@db.example.com:5432/documenso?sslmode=require
```
**With special characters in password:**
URL-encode special characters in passwords. For example, `p@ss#word` becomes `p%40ss%23word`:
```
postgresql://documenso:p%40ss%23word@localhost:5432/documenso
```
## Environment Variables
Documenso uses two database connection variables:
| Variable | Purpose |
| ---------------------------------- | --------------------------------------------------- |
| `NEXT_PRIVATE_DATABASE_URL` | Primary connection for application queries |
| `NEXT_PRIVATE_DIRECT_DATABASE_URL` | Direct connection for migrations and schema changes |
### Basic Configuration
When not using a connection pooler, set both variables to the same value:
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://user:password@host:5432/documenso
NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://user:password@host:5432/documenso
```
### Automatic Detection
Documenso automatically detects common database environment variable formats used by hosting providers:
| Provider Variable | Maps To |
| -------------------------- | ---------------------------------- |
| `DATABASE_URL` | `NEXT_PRIVATE_DATABASE_URL` |
| `POSTGRES_URL` | `NEXT_PRIVATE_DATABASE_URL` |
| `POSTGRES_PRISMA_URL` | `NEXT_PRIVATE_DATABASE_URL` |
| `DATABASE_URL_UNPOOLED` | `NEXT_PRIVATE_DIRECT_DATABASE_URL` |
| `POSTGRES_URL_NON_POOLING` | `NEXT_PRIVATE_DIRECT_DATABASE_URL` |
If your hosting provider sets these variables, Documenso will use them automatically.
## Connection Pooling
Connection pooling improves performance by reusing database connections instead of creating new ones for each request.
### When to Use Pooling
Use connection pooling when:
- Running multiple application instances
- Deploying to serverless environments
- Handling high concurrent request volumes
- Your database has connection limits
### PgBouncer Configuration
When using PgBouncer or similar poolers, configure two connection strings:
1. **Pooled connection** for application queries
2. **Direct connection** for migrations (bypasses the pooler)
```bash
# Pooled connection (through PgBouncer)
NEXT_PRIVATE_DATABASE_URL=postgresql://user:password@pooler-host:6432/documenso?pgbouncer=true
# Direct connection (bypasses PgBouncer)
NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://user:password@db-host:5432/documenso
```
<Callout type="warn">
Migrations must use a direct connection. Running migrations through a connection pooler will fail.
</Callout>
### Prisma Connection Pool
Documenso uses Prisma, which maintains its own connection pool. Configure pool size with connection string parameters:
```
postgresql://user:password@host:5432/documenso?connection_limit=10&pool_timeout=30
```
| Parameter | Description | Default |
| ------------------ | ---------------------------------------- | ------- |
| `connection_limit` | Maximum connections in the pool | 10 |
| `pool_timeout` | Seconds to wait for available connection | 10 |
## SSL/TLS Connections
### Enabling SSL
Add SSL parameters to your connection string:
```
postgresql://user:password@host:5432/documenso?sslmode=require
```
### SSL Modes
| Mode | Description |
| ------------- | --------------------------------------------------- |
| `disable` | No SSL (not recommended for production) |
| `allow` | Try non-SSL first, fall back to SSL |
| `prefer` | Try SSL first, fall back to non-SSL |
| `require` | Require SSL, but don't verify certificate |
| `verify-ca` | Require SSL and verify server certificate |
| `verify-full` | Require SSL, verify certificate, and check hostname |
For production, use `require` at minimum. Use `verify-full` when your CA certificate is available.
### Custom Certificates
When connecting to databases with self-signed or private CA certificates:
```
postgresql://user:password@host:5432/documenso?sslmode=verify-full&sslrootcert=/path/to/ca.crt
```
For Docker deployments, mount the certificate file:
```bash
docker run -d \
-v /path/to/ca.crt:/etc/ssl/certs/db-ca.crt:ro \
-e NEXT_PRIVATE_DATABASE_URL="postgresql://user:password@host:5432/documenso?sslmode=verify-full&sslrootcert=/etc/ssl/certs/db-ca.crt" \
documenso/documenso:latest
```
## Running Migrations
Database migrations update your schema when upgrading Documenso.
### Automatic Migrations
When running Documenso via Docker, migrations run automatically on container startup. No manual intervention is required.
### Manual Migrations
For manual deployments or troubleshooting:
```bash
# Apply pending migrations
npm run prisma:migrate-deploy
# Or using npx directly
npx prisma migrate deploy
```
<Callout type="info">
Always back up your database before running migrations, especially for major version upgrades.
</Callout>
### Migration Commands
| Command | Purpose |
| ----------------------- | ----------------------------------------- |
| `prisma:migrate-deploy` | Apply pending migrations (production) |
| `prisma:migrate-dev` | Create and apply migrations (development) |
| `prisma:migrate-reset` | Reset database and apply all migrations |
### Troubleshooting Migrations
<Accordions type="multiple">
<Accordion title="Migration failed midway">
Check the `_prisma_migrations` table:
```sql
SELECT * FROM _prisma_migrations WHERE finished_at IS NULL;
```
To retry, fix the underlying issue (disk space, permissions, etc.), mark as rolled back:
```sql
UPDATE _prisma_migrations SET rolled_back_at = NOW() WHERE migration_name = 'failed_migration_name';
```
Run migrations again.
</Accordion>
<Accordion title="Connection timeout during migration">
Use the direct database URL and increase timeout:
```bash
NEXT_PRIVATE_DIRECT_DATABASE_URL="postgresql://user:password@host:5432/documenso?connect_timeout=60"
```
</Accordion>
</Accordions>
## Managed Database Services
<Accordions type="multiple">
<Accordion title="Supabase">
Supabase provides PostgreSQL with built-in connection pooling via Supavisor.
**Configuration:**
```bash
# Pooled connection (Session mode - port 5432)
NEXT_PRIVATE_DATABASE_URL=postgresql://postgres.[project-ref]:[password]@aws-0-[region].pooler.supabase.com:5432/postgres
# Direct connection for migrations (port 5432, direct host)
NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://postgres:[password]@db.[project-ref].supabase.co:5432/postgres
```
Find your connection strings in the Supabase dashboard under **Settings > Database > Connection string**.
</Accordion>
<Accordion title="Neon">
Neon provides serverless PostgreSQL with automatic scaling.
**Configuration:**
```bash
# Pooled connection
NEXT_PRIVATE_DATABASE_URL=postgresql://[user]:[password]@[endpoint]-pooler.region.aws.neon.tech/documenso?sslmode=require
# Direct connection for migrations
NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://[user]:[password]@[endpoint].region.aws.neon.tech/documenso?sslmode=require
```
The pooler endpoint includes `-pooler` in the hostname.
</Accordion>
<Accordion title="AWS RDS">
**Configuration:**
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://documenso:[password]@your-instance.region.rds.amazonaws.com:5432/documenso?sslmode=require
NEXT_PRIVATE_DIRECT_DATABASE_URL=postgresql://documenso:[password]@your-instance.region.rds.amazonaws.com:5432/documenso?sslmode=require
```
**Recommended settings:**
- Instance class: `db.t3.medium` or larger for production
- Storage: General Purpose SSD (gp3), minimum 20GB
- Enable automated backups with 7+ day retention
- Enable Multi-AZ for high availability
</Accordion>
<Accordion title="Google Cloud SQL">
**Configuration:**
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://documenso:[password]@/documenso?host=/cloudsql/[project]:[region]:[instance]
```
When connecting via Cloud SQL Proxy, use Unix socket connections.
For public IP connections:
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://documenso:[password]@[public-ip]:5432/documenso?sslmode=require
```
</Accordion>
<Accordion title="Azure Database for PostgreSQL">
**Configuration:**
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://documenso@[server-name]:[password]@[server-name].postgres.database.azure.com:5432/documenso?sslmode=require
```
Note: Azure requires the username format `user@servername`.
</Accordion>
<Accordion title="DigitalOcean Managed Databases">
**Configuration:**
```bash
NEXT_PRIVATE_DATABASE_URL=postgresql://doadmin:[password]@[cluster-host]:25060/documenso?sslmode=require
```
DigitalOcean uses port 25060 by default and requires SSL.
</Accordion>
</Accordions>
## Backup Recommendations
### Backup Strategies
| Strategy | Frequency | Retention | Use Case |
| ---------------------- | ------------ | ----------- | ---------------------- |
| Automated snapshots | Daily | 7-30 days | Point-in-time recovery |
| Logical backups | Daily/Weekly | 30-90 days | Long-term retention |
| Continuous replication | Real-time | 24-72 hours | Disaster recovery |
### PostgreSQL Backup Commands
**Create a logical backup:**
```bash
pg_dump -h host -U user -d documenso -F c -f documenso_backup.dump
```
**Restore from backup:**
```bash
pg_restore -h host -U user -d documenso -c documenso_backup.dump
```
### Managed Service Backups
Most managed database services provide automated backups:
<Tabs items={['Supabase', 'Neon', 'AWS RDS', 'Google Cloud SQL', 'Azure']}>
<Tab value="Supabase">Daily backups with point-in-time recovery (Pro plan)</Tab>
<Tab value="Neon">Automatic branching for instant recovery</Tab>
<Tab value="AWS RDS">Automated backups with configurable retention</Tab>
<Tab value="Google Cloud SQL">Automated and on-demand backups</Tab>
<Tab value="Azure">Automatic backups with geo-redundancy options</Tab>
</Tabs>
<Callout type="warn">
Always test your backup restoration process. Untested backups may not work when needed.
</Callout>
## Performance Tuning
### PostgreSQL Configuration
Key parameters for Documenso workloads:
| Parameter | Recommended Value | Description |
| ---------------------- | ----------------- | ------------------------------------- |
| `shared_buffers` | 25% of RAM | Memory for caching data |
| `effective_cache_size` | 75% of RAM | Planner's estimate of available cache |
| `work_mem` | 64MB-256MB | Memory per sort/hash operation |
| `maintenance_work_mem` | 512MB-1GB | Memory for maintenance operations |
| `max_connections` | 100-200 | Maximum concurrent connections |
### Connection Limits
Calculate your connection limit:
```
max_connections = (application_instances × connection_pool_size) + admin_overhead
```
Example: 3 app instances with pool size 10 = `(3 × 10) + 10 = 40` connections minimum.
### Indexing
Documenso includes necessary indexes by default. Additional indexes may help for:
- Custom reporting queries
- High-volume document searches
- Audit log analysis
Check for slow queries:
```sql
SELECT query, calls, mean_time, total_time
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 10;
```
### Monitoring
Monitor these metrics:
| Metric | Warning Threshold | Action |
| -------------------- | ----------------- | ------------------------------- |
| Connection usage | > 80% | Increase limits or add pooling |
| Disk usage | > 80% | Add storage or archive old data |
| Cache hit ratio | < 95% | Increase `shared_buffers` |
| Long-running queries | > 30 seconds | Optimize query or add indexes |
## Troubleshooting
<Accordions type="multiple">
<Accordion title="Connection refused">
Causes:
- PostgreSQL not running
- Incorrect host or port
- Firewall blocking
Solutions:
- Verify PostgreSQL is running with `pg_isready -h host -p 5432`
- Check the connection string
- Verify firewall rules
with `pg_isready -h host -p 5432`, check the connection string, verify firewall rules.
</Accordion>
<Accordion title="Authentication failed">
Causes:
- Incorrect password
- User doesn't exist
- Password contains special characters
Solutions:
- Reset password with `ALTER USER documenso WITH PASSWORD 'newpassword';`
- Verify credentials in `pg_hba.conf`
- Verify URL-encoded special characters
</Accordion>
<Accordion title="SSL connection required">
Add SSL mode to your connection string:
```bash
postgresql://user:password@host:5432/documenso?sslmode=require
```
</Accordion>
<Accordion title="Too many connections">
Causes:
- Connection pool exhausted
- Connections not released
- Multiple instances exceeding limits
Solutions:
- Reduce `connection_limit`
- Increase `max_connections`
- Implement PgBouncer
</Accordion>
<Accordion title="Database does not exist">
Create the database:
```sql
CREATE DATABASE documenso;
GRANT ALL PRIVILEGES ON DATABASE documenso TO documenso;
```
</Accordion>
<Accordion title="Permission denied">
Grant permissions:
```sql
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO documenso;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO documenso;
```
</Accordion>
</Accordions>
---
## See Also
- [Environment Variables](/docs/self-hosting/configuration/environment) - Complete configuration reference
- [Storage Configuration](/docs/self-hosting/configuration/storage) - Set up document storage
- [Backups](/docs/self-hosting/maintenance/backups) - Backup strategies and procedures
- [Upgrades](/docs/self-hosting/maintenance/upgrades) - Upgrade procedures and migration handling