Databases
Provision managed databases in seconds. The platform supports MySQL, PostgreSQL, and Redis, all running as Docker containers on the same internal network as your applications.
Available Engines
MySQL
Version 8.0Reliable relational database with full SQL support. Best for traditional web applications, CMS platforms, and e-commerce.
PostgreSQL
Version 16Advanced relational database with JSONB, full-text search, and extensions. Best for complex applications and analytics.
Redis
Version 7In-memory key-value store. Best for caching, session storage, queues, rate limiting, and real-time features.
Creating a Database
Via the Dashboard
- Navigate to Databases in the sidebar
- Click "Create Database"
- Choose an engine (MySQL, PostgreSQL, or Redis)
- Enter a name for the database (used as the container name)
- Optionally set a custom root/admin password (one will be generated if not provided)
- Click "Create"
The database will be provisioned in a few seconds. Connection details will be shown immediately.
Connection Strings
Each database gets a connection string that you should store as an environment variable in your project. The format depends on the engine:
MySQL
mysql://root:<password>@<container-name>:3306/<database-name> # Example: mysql://root:s3cretPass@myapp-mysql:3306/myapp
PostgreSQL
postgresql://postgres:<password>@<container-name>:5432/<database-name> # Example: postgresql://postgres:s3cretPass@myapp-postgres:5432/myapp
Redis
redis://default:<password>@<container-name>:6379 # Example (no auth): redis://myapp-redis:6379 # Example (with password): redis://default:s3cretPass@myapp-redis:6379
Tip: Store the connection string as an environment variable (e.g., DATABASE_URL) in your project settings. The platform encrypts it at rest and injects it at deploy time.
Code Examples
Node.js
MySQL (mysql2)
javascriptimport mysql from 'mysql2/promise';
const connection = await mysql.createConnection(
process.env.DATABASE_URL
);
const [rows] = await connection.execute('SELECT * FROM users');
console.log(rows);PostgreSQL (pg)
javascriptimport pg from 'pg';
const pool = new pg.Pool({
connectionString: process.env.DATABASE_URL,
});
const result = await pool.query('SELECT * FROM users');
console.log(result.rows);PostgreSQL (Prisma)
javascript// prisma/schema.prisma
// datasource db {
// provider = "postgresql"
// url = env("DATABASE_URL")
// }
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
const users = await prisma.user.findMany();Redis (ioredis)
javascriptimport Redis from 'ioredis';
const redis = new Redis(process.env.REDIS_URL);
await redis.set('key', 'value');
const value = await redis.get('key');
console.log(value); // "value"Python
MySQL (pymysql)
pythonimport pymysql
import os
connection = pymysql.connect(
host=os.environ.get("DB_HOST", "myapp-mysql"),
port=3306,
user="root",
password=os.environ["DB_PASSWORD"],
database="myapp",
)
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM users")
rows = cursor.fetchall()
print(rows)PostgreSQL (psycopg2)
pythonimport psycopg2
import os
conn = psycopg2.connect(os.environ["DATABASE_URL"])
cur = conn.cursor()
cur.execute("SELECT * FROM users")
rows = cur.fetchall()
print(rows)PostgreSQL (SQLAlchemy)
pythonfrom sqlalchemy import create_engine
import os
engine = create_engine(os.environ["DATABASE_URL"])
with engine.connect() as conn:
result = conn.execute("SELECT * FROM users")
for row in result:
print(row)Redis
pythonimport redis
import os
r = redis.from_url(os.environ["REDIS_URL"])
r.set("key", "value")
value = r.get("key")
print(value) # b"value"PHP
MySQL (PDO)
php<?php
$dsn = 'mysql:host=myapp-mysql;port=3306;dbname=myapp';
$pdo = new PDO($dsn, 'root', getenv('DB_PASSWORD'));
$stmt = $pdo->query('SELECT * FROM users');
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($rows);PostgreSQL (PDO)
php<?php
$dsn = 'pgsql:host=myapp-postgres;port=5432;dbname=myapp';
$pdo = new PDO($dsn, 'postgres', getenv('DB_PASSWORD'));
$stmt = $pdo->query('SELECT * FROM users');
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($rows);Redis (phpredis)
php<?php
$redis = new Redis();
$redis->connect('myapp-redis', 6379);
$redis->set('key', 'value');
$value = $redis->get('key');
echo $value; // "value"Go
MySQL (database/sql)
gopackage main
import (
"database/sql"
"fmt"
"os"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := sql.Open("mysql", os.Getenv("DATABASE_URL"))
if err != nil {
panic(err)
}
defer db.Close()
rows, err := db.Query("SELECT id, name FROM users")
if err != nil {
panic(err)
}
defer rows.Close()
for rows.Next() {
var id int
var name string
rows.Scan(&id, &name)
fmt.Printf("User: %d - %s\n", id, name)
}
}PostgreSQL (pgx)
gopackage main
import (
"context"
"fmt"
"os"
"github.com/jackc/pgx/v5"
)
func main() {
ctx := context.Background()
conn, err := pgx.Connect(ctx, os.Getenv("DATABASE_URL"))
if err != nil {
panic(err)
}
defer conn.Close(ctx)
rows, _ := conn.Query(ctx, "SELECT id, name FROM users")
for rows.Next() {
var id int
var name string
rows.Scan(&id, &name)
fmt.Printf("User: %d - %s\n", id, name)
}
}Redis (go-redis)
gopackage main
import (
"context"
"fmt"
"os"
"github.com/redis/go-redis/v9"
)
func main() {
ctx := context.Background()
opt, _ := redis.ParseURL(os.Getenv("REDIS_URL"))
rdb := redis.NewClient(opt)
rdb.Set(ctx, "key", "value", 0)
val, _ := rdb.Get(ctx, "key").Result()
fmt.Println(val) // "value"
}Ruby
MySQL (mysql2)
rubyrequire 'mysql2'
client = Mysql2::Client.new(
host: 'myapp-mysql',
username: 'root',
password: ENV['DB_PASSWORD'],
database: 'myapp'
)
results = client.query('SELECT * FROM users')
results.each do |row|
puts row
endPostgreSQL (pg)
rubyrequire 'pg'
conn = PG.connect(ENV['DATABASE_URL'])
result = conn.exec('SELECT * FROM users')
result.each do |row|
puts row
endRedis
rubyrequire 'redis'
redis = Redis.new(url: ENV['REDIS_URL'])
redis.set('key', 'value')
value = redis.get('key')
puts value # "value"Connecting from Your App
Internal Network
All containers (apps and databases) run on the same Docker network. Your app connects to the database using the container name as the hostname. No ports need to be exposed externally.
Internal connection (recommended)
# From inside your app container: DATABASE_URL=postgresql://postgres:pass@myapp-postgres:5432/myapp # The hostname "myapp-postgres" resolves to the database container's IP # on the internal Docker network. This is fast and secure.
External Access
By default, database ports are not exposed to the internet. If you need to connect from outside (e.g., a local development machine), use SSH tunneling (see below) or enable external access in the database settings.
Security warning: Exposing database ports to the internet is not recommended for production databases. Use SSH tunneling or VPN instead.
SSH Tunneling for Local Development
Use an SSH tunnel to securely connect to your database from your local machine:
SSH tunnel example (PostgreSQL)
bash# Forward local port 5433 to the remote PostgreSQL container ssh -L 5433:myapp-postgres:5432 user@system.rouic.com # Then connect locally: psql "postgresql://postgres:pass@localhost:5433/myapp"
SSH tunnel example (MySQL)
bash# Forward local port 3307 to the remote MySQL container ssh -L 3307:myapp-mysql:3306 user@system.rouic.com # Then connect locally: mysql -h 127.0.0.1 -P 3307 -u root -p myapp
Backups and Restores
Creating backups
Navigate to the database detail page in the dashboard and click "Create Backup". Backups are stored as compressed SQL dumps (MySQL/PostgreSQL) or RDB snapshots (Redis).
Scheduled backups
Enable scheduled backups in the database settings. Choose a frequency (daily, weekly) and a retention period. Old backups are automatically deleted.
Restoring from backup
Select a backup from the list and click "Restore". This will stop the database, replace the data volume with the backup, and restart it. All current data will be overwritten.
Warning: Restoring a backup is a destructive operation. Make sure you have a recent backup of the current data before restoring.
Query Browser
The built-in query browser lets you run SQL queries directly from the dashboard. Navigate to a database and click the "Query" tab.
- Run SELECT, INSERT, UPDATE, DELETE, and DDL statements
- Results are displayed in a paginated table
- Query history is saved per database
- For Redis, you can run any Redis command (GET, SET, KEYS, etc.)
Note: The query browser is intended for debugging and administrative tasks. For application queries, always connect from your app using the connection string.
Best Practices
Use connection pooling
Limit the number of database connections your application opens. Use a connection pool (e.g., PgBouncer for PostgreSQL, built-in pooling in mysql2/pg libraries).
Store connection strings as env vars
Never hardcode database credentials in your source code. Use environment variables that are encrypted by the platform.
Run migrations on deploy
Add a migration step to your Dockerfile or deploy script. Prisma: prisma migrate deploy. Django: python manage.py migrate.
Enable backups before going live
Always enable scheduled backups for production databases. Test restoring from a backup at least once.
Use Redis for caching, not primary storage
Redis data can be lost on restart (unless persistence is configured). Use it for caching and ephemeral data.
Monitor connection counts
Check the metrics dashboard for active connection counts. Running out of connections is a common issue in production.
Next up
Object Storage โPrevious
Deploying Apps