Documentation Index
Fetch the complete documentation index at: https://mintlify.com/medusajs/medusa/llms.txt
Use this file to discover all available pages before exploring further.
Database Setup
Medusa uses PostgreSQL as its primary database. This guide covers database setup, configuration, and migrations.
PostgreSQL Requirements
- PostgreSQL version: 12 or higher (PostgreSQL 14+ recommended)
- Database user: Must have create privileges
- Extensions: No special extensions required by default
Database Connection
Connection URL
Medusa connects to PostgreSQL using a connection URL:
DATABASE_URL=postgres://[user][:password]@[host][:port]/[dbname]
Where:
[user]: Your PostgreSQL username (required)
[:password]: User password (optional, prefix with :)
[host]: Database host (required, e.g., localhost)
[:port]: PostgreSQL port (optional, default: 5432, prefix with :)
[dbname]: Database name (required)
Example Connection URLs
# Local development
DATABASE_URL=postgres://postgres@localhost/medusa-store
# With password
DATABASE_URL=postgres://postgres:password123@localhost/medusa-store
# Custom port
DATABASE_URL=postgres://postgres:password123@localhost:5433/medusa-store
# Remote database
DATABASE_URL=postgres://user:pass@db.example.com:5432/medusa-production
# With SSL (add ?ssl=true or ?sslmode=require)
DATABASE_URL=postgres://user:pass@db.example.com:5432/medusa?sslmode=require
Creating a Database
Using PostgreSQL CLI
# Connect to PostgreSQL
psql -U postgres
# Create database
CREATE DATABASE medusa_store;
# Create user (optional)
CREATE USER medusa_user WITH PASSWORD 'secure_password';
# Grant privileges
GRANT ALL PRIVILEGES ON DATABASE medusa_store TO medusa_user;
Using createdb Command
createdb -U postgres medusa_store
Medusa can automatically create the database on first run if it doesn’t exist and the user has create privileges.
Database Configuration
Basic Configuration
import { defineConfig } from "@medusajs/utils"
export default defineConfig({
projectConfig: {
databaseUrl: process.env.DATABASE_URL,
},
})
Advanced Configuration
import { defineConfig } from "@medusajs/utils"
export default defineConfig({
projectConfig: {
// Connection URL
databaseUrl: process.env.DATABASE_URL,
// Schema (default: "public")
databaseSchema: "public",
// Connection pool options
databaseDriverOptions: {
pool: {
// Minimum connections in pool
min: 2,
// Maximum connections in pool
max: 10,
// Idle timeout in milliseconds
idleTimeoutMillis: 30000,
// Reap interval in milliseconds
reapIntervalMillis: 1000,
// Create retry interval in milliseconds
createRetryIntervalMillis: 200,
},
},
},
})
Connection Pool Sizing
Recommended pool sizes based on your deployment:
- Development:
min: 2, max: 5
- Production (single instance):
min: 2, max: 10
- Production (multiple instances):
min: 2, max: 5 per instance
Be careful with connection pool sizes. PostgreSQL has a maximum connection limit (default: 100). If you have multiple application instances, ensure the total connections don’t exceed the limit.
SSL Configuration
For production databases, enable SSL:
# Basic SSL
DATABASE_URL=postgres://user:pass@host:5432/db?sslmode=require
# Verify CA certificate
DATABASE_URL=postgres://user:pass@host:5432/db?sslmode=verify-ca
# Verify full SSL
DATABASE_URL=postgres://user:pass@host:5432/db?sslmode=verify-full
SSL modes:
disable: No SSL
require: SSL required, but don’t verify certificate
verify-ca: Verify server certificate against CA
verify-full: Verify certificate and hostname
Database Migrations
Migrations ensure your database schema is up-to-date with your Medusa version and modules.
Running Migrations
Before starting your application, run migrations:
This command:
- Creates the database if it doesn’t exist
- Creates the migrations table
- Runs all pending module migrations
- Synchronizes link definitions between modules
- Executes migration scripts
Migration Options
# Run migrations (default)
npx medusa db:migrate
# Skip link synchronization
npx medusa db:migrate --skip-links
# Skip migration scripts
npx medusa db:migrate --skip-scripts
# Execute all link migrations (not just safe ones)
npx medusa db:migrate --execute-all-links
# Set migration concurrency
npx medusa db:migrate --concurrency 5
Always run migrations before starting your application in production. Running without migrations will cause errors.
Migration Process
Medusa uses MikroORM for migrations. The migration process:
- Module Migrations: Each module maintains its own migrations
- Link Synchronization: Creates join tables for module relationships
- Migration Scripts: Custom data transformations and updates
Checking Migration Status
Migrations are tracked in the mikro_orm_migrations table:
-- Check migration status
SELECT * FROM mikro_orm_migrations ORDER BY executed_at DESC;
Database Schemas
By default, Medusa uses the public schema. You can configure a custom schema:
export default defineConfig({
projectConfig: {
databaseUrl: process.env.DATABASE_URL,
databaseSchema: "medusa", // Custom schema
},
})
Create the schema before running migrations:
Database Backup and Restore
Backup Database
# Backup to file
pg_dump -U postgres -d medusa_store -F c -f medusa_backup.dump
# Backup with compression
pg_dump -U postgres -d medusa_store -F c -Z 9 -f medusa_backup.dump
# Backup specific schema
pg_dump -U postgres -d medusa_store -n public -F c -f medusa_backup.dump
Restore Database
# Restore from backup
pg_restore -U postgres -d medusa_store -c medusa_backup.dump
# Create database and restore
createdb -U postgres medusa_store
pg_restore -U postgres -d medusa_store medusa_backup.dump
Always test your backup and restore process before you need it in production.
Indexes
Medusa automatically creates necessary indexes through migrations. For custom optimizations:
-- Check missing indexes
SELECT schemaname, tablename, attname, n_distinct, correlation
FROM pg_stats
WHERE schemaname = 'public'
ORDER BY n_distinct DESC;
-- Create custom index
CREATE INDEX CONCURRENTLY idx_custom ON your_table(column_name);
Connection Pooling
Use connection pooling for better performance:
export default defineConfig({
projectConfig: {
databaseDriverOptions: {
pool: {
min: 2,
max: 10,
idleTimeoutMillis: 30000,
},
},
},
})
Monitor slow queries:
-- Enable query logging
ALTER DATABASE medusa_store SET log_min_duration_statement = 1000;
-- View slow queries
SELECT * FROM pg_stat_statements
ORDER BY mean_exec_time DESC
LIMIT 10;
Troubleshooting
Connection Refused
Error: connect ECONNREFUSED 127.0.0.1:5432
Solutions:
- Check if PostgreSQL is running:
sudo systemctl status postgresql
- Verify the host and port in
DATABASE_URL
- Check firewall rules
Authentication Failed
Error: password authentication failed for user "postgres"
Solutions:
- Verify username and password in
DATABASE_URL
- Check
pg_hba.conf for authentication settings
- Reset user password if needed
Database Does Not Exist
Error: database "medusa_store" does not exist
Solutions:
- Create the database manually
- Ensure the user has create privileges for auto-creation
- Check the database name in
DATABASE_URL
Too Many Connections
Error: sorry, too many clients already
Solutions:
- Reduce connection pool size in
databaseDriverOptions
- Increase PostgreSQL
max_connections setting
- Use a connection pooler like PgBouncer
Migration Failures
Solutions:
- Check PostgreSQL logs for details
- Ensure user has necessary privileges
- Verify no concurrent migration processes
- Check for conflicting data or constraints
Production Best Practices
Security
- Use strong passwords: Generate random, complex passwords
- Limit privileges: Grant only necessary permissions
- Enable SSL: Use SSL for all connections
- Network isolation: Use private networks or VPNs
- Regular backups: Automate daily backups
Monitoring
- Connection count: Monitor active connections
- Query performance: Track slow queries
- Disk usage: Monitor database size
- Replication lag: If using replication
Maintenance
-- Vacuum and analyze
VACUUM ANALYZE;
-- Reindex database
REINDEX DATABASE medusa_store;
-- Check database size
SELECT pg_size_pretty(pg_database_size('medusa_store'));
Schedule regular VACUUM and ANALYZE operations during low-traffic periods to maintain optimal performance.
Multiple Database Support
Medusa supports module-specific databases:
import { Modules } from "@medusajs/utils"
export default defineConfig({
projectConfig: {
databaseUrl: process.env.DATABASE_URL,
},
modules: [
{
key: Modules.PRODUCT,
resolve: "@medusajs/product",
options: {
// Custom database for product module
databaseUrl: process.env.PRODUCT_DATABASE_URL,
},
},
],
})
Environment variables:
# Shared database
DATABASE_URL=postgres://localhost/medusa_shared
# Module-specific database
PRODUCT_DATABASE_URL=postgres://localhost/medusa_products