Databases in Coolify
Coolify treats databases as first-class resources. Instead of manually running docker run postgres, you click a button, configure a few options, and get a production-ready database with:
- Persistent storage that survives container restarts
- Internal networking for secure app connections
- Backup scheduling with multiple destinations
- Resource limits to prevent runaway queries
Supported Databases
PostgreSQL, MySQL/MariaDB, MongoDB, Redis, KeyDB, Dragonfly, ClickHouse, and more.
Deploying PostgreSQL
PostgreSQL is the go-to choice for most applications. Let's spin one up.
Create the Database
- Go to Projects → Select your project (or create one called "Databases")
- Click Add Resource → Database → PostgreSQL
- Configure the basics (see table below)
- Click Create
| Setting | Recommended Value |
|---|---|
| Name | postgres-main |
| Version | 16 (latest stable) |
| Default Database | app_production |
| Username | app_user |
| Password | (auto-generated or set your own) |
Resource Configuration
Recommended settings for a 4GB RamNode VPS:
| Setting | Value | Why |
|---|---|---|
| Memory Limit | 1G | Prevents Postgres from starving other services |
| Memory Reservation | 512M | Guaranteed minimum |
| CPU Limit | 2 | Allows burst for complex queries |
Persistent Storage: Coolify automatically creates a persistent volume at /var/lib/postgresql/data. Data survives container restarts, upgrades, and redeployments.
Connecting Apps to Databases
Your apps and databases run in Docker containers. Coolify makes connecting them straightforward through internal networking.
Internal Connection URLs
Every database resource shows its connection details:
Internal URL: postgres-main:5432
Database: app_production
Username: app_user
Password: ••••••••••The internal URL uses the container name as the hostname. This works because Coolify places resources in the same Docker network.
Configure Your App's Environment
DATABASE_URL=postgresql://app_user:your-password@postgres-main:5432/app_productionOr individual variables if your framework prefers:
DB_HOST=postgres-main
DB_PORT=5432
DB_NAME=app_production
DB_USER=app_user
DB_PASSWORD=your-passwordConnection String Formats
Node.js (pg, Prisma, Drizzle)
postgresql://user:password@postgres-main:5432/databaseDjango (settings.py)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'HOST': os.environ.get('DB_HOST'),
'PORT': os.environ.get('DB_PORT', 5432),
'NAME': os.environ.get('DB_NAME'),
'USER': os.environ.get('DB_USER'),
'PASSWORD': os.environ.get('DB_PASSWORD'),
}
}Laravel (.env)
DB_CONNECTION=pgsql
DB_HOST=postgres-main
DB_PORT=5432
DB_DATABASE=app_production
DB_USERNAME=app_user
DB_PASSWORD=your-passwordDeploying MySQL/MariaDB
Some applications require MySQL. The process is nearly identical to PostgreSQL.
- Add Resource → Database → MySQL (or MariaDB)
- Configure (see table below)
- Click Create
| Setting | Value |
|---|---|
| Name | mysql-main |
| Version | 8.0 |
| Root Password | (set a strong password) |
| Default Database | app_production |
MySQL Connection Strings
mysql://app_user:password@mysql-main:3306/app_productiondefine('DB_HOST', 'mysql-main');
define('DB_NAME', 'app_production');
define('DB_USER', 'app_user');
define('DB_PASSWORD', 'your-password');Deploying Redis
Redis serves as a cache, session store, message broker, or queue backend. It's essential for scaling applications.
- Add Resource → Database → Redis
- Configure: Name (
redis-cache), Version (7), Password - Click Create
Redis Connection
redis://:your-password@redis-cache:6379const redis = new Redis({
host: 'redis-cache',
port: 6379,
password: process.env.REDIS_PASSWORD
});import redis
r = redis.Redis(host='redis-cache', port=6379, password=os.environ['REDIS_PASSWORD'])Redis for Different Use Cases
Consider separate Redis instances for different purposes:
| Instance | Use Case | Memory Limit |
|---|---|---|
redis-cache | Application caching | 256M-512M |
redis-sessions | User session storage | 128M-256M |
redis-queue | Job queue (Sidekiq, Bull) | 256M-512M |
Deploying MongoDB
For document-based storage or when your app requires MongoDB specifically.
- Add Resource → Database → MongoDB
- Configure: Name (
mongo-main), Version (7), Root Username, Root Password - Click Create
MongoDB Connection
mongodb://admin:password@mongo-main:27017/app_production?authSource=adminmongoose.connect(process.env.MONGODB_URL);client = MongoClient(os.environ['MONGODB_URL'])Database Backups
Data without backups is data waiting to be lost. Coolify provides automated backup scheduling with multiple destination options.
Enable Scheduled Backups
- Go to your database resource → Backups
- Click Add Backup
- Configure the schedule (see table below)
| Schedule | Cron Expression | Use Case |
|---|---|---|
| Every 6 hours | 0 */6 * * * | High-change production data |
| Daily at 3 AM | 0 3 * * * | Standard production |
| Weekly Sunday 2 AM | 0 2 * * 0 | Low-change databases |
💾 Local Backups
Stored on your VPS filesystem at /data/coolify/backups. Set retention to keep last 7 backups.
Warning: Local backups don't protect against disk failure. Use S3-compatible storage for disaster recovery.
☁️ S3-Compatible Storage
Works with AWS S3, Backblaze B2 (just $0.006/GB), Wasabi, MinIO, or any S3-compatible provider.
- Go to Settings → Storage → Add Storage
- Configure endpoint, bucket, region, access key, secret key
- Assign to your database backups
Backup Verification
Periodically test your backups:
# Spin up a temporary container
docker run -d --name test-restore -e POSTGRES_PASSWORD=test postgres:16
docker cp backup.sql test-restore:/backup.sql
docker exec test-restore psql -U postgres -f /backup.sql
docker exec test-restore psql -U postgres -c "SELECT COUNT(*) FROM users;"
docker rm -f test-restoreExternal Database Access
Sometimes you need to connect directly—running migrations, using a GUI client, or debugging.
⚠️ Expose Database Port (Temporary)
- Database settings → Network
- Enable Publicly Accessible
- Set a non-standard port (e.g.,
35432)
Disable when not needed. Use strong passwords and consider IP allowlisting.
✅ SSH Tunnel (Recommended)
Safer than exposing ports—tunnel through SSH:
ssh -L 5432:postgres-main:5432 root@your-server-ipConnect your local client to localhost:5432. Connection is encrypted and the database port stays closed.
GUI clients with built-in SSH: TablePlus, DBeaver, DataGrip, pgAdmin
Running Migrations
Most frameworks include migration tools. Run them either during deployment or manually.
Option 1: Post-Deploy Command
Add to your app's settings. Runs automatically after each successful deployment:
# Node.js (Prisma)
npx prisma migrate deploy
# Python (Alembic)
alembic upgrade head
# Laravel
php artisan migrate --force
# Rails
rails db:migrateOption 2: One-Off Commands
For manual migration runs:
# SSH to your server
ssh root@your-server-ip
# Execute command in your app's container
docker exec -it <app-container-id> npx prisma migrate deployOr use Coolify's Execute Command feature in the resource settings.
Database Management Tips
🔄 Connection Pooling
If your app opens many connections, deploy PgBouncer as a separate service. Benefits: handles thousands of connections, reduces PostgreSQL memory usage, faster connection establishment.
📊 Basic Monitoring
# PostgreSQL: Active connections
docker exec -it <postgres> psql -U postgres -c "SELECT * FROM pg_stat_activity;"
# MySQL: Process list
docker exec -it <mysql> mysql -u root -p -e "SHOW PROCESSLIST;"
# Redis: Memory and stats
docker exec -it <redis> redis-cli INFOFor comprehensive monitoring, deploy Prometheus + Grafana (covered in Part 6).
📁 Multiple Databases per Instance
Save resources by running staging and production in one instance:
# PostgreSQL
docker exec -it <postgres> psql -U postgres -c "CREATE DATABASE staging_db;"
# MySQL
docker exec -it <mysql> mysql -u root -p -e "CREATE DATABASE staging_db;"What's Next
You now have production databases running alongside your applications, connected through secure internal networking, with automated backups protecting your data.
In Part 4, we'll deploy complete application stacks using Docker Compose—spinning up popular self-hosted apps like Plausible Analytics, n8n, Uptime Kuma, and more with just a few clicks.
