Elder uses PyDAL (Python Database Abstraction Layer) for database operations, providing support for 18+ different database systems with a unified API.
Reference: https://py4web.com/_documentation/static/en/chapter-07.html
Elder is configured for PostgreSQL by default. Set these environment variables:
DB_TYPE=postgres
DB_HOST=localhost
DB_PORT=5432
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=your_secure_password
DB_POOL_SIZE=10Or use a full connection URI:
DATABASE_URL=postgres://elder:password@localhost:5432/elderElder supports two configuration methods:
Set a single DATABASE_URL environment variable with the complete connection string:
DATABASE_URL=postgres://user:password@host:port/databaseThis takes precedence over individual component variables.
Configure database connection using separate environment variables:
| Variable | Description | Default |
|---|---|---|
DB_TYPE |
Database type (see supported types below) | postgres |
DB_HOST |
Database host/server | localhost |
DB_PORT |
Database port | 5432 |
DB_NAME |
Database name | elder |
DB_USER |
Database username | elder |
DB_PASSWORD |
Database password | elder |
DB_POOL_SIZE |
Connection pool size | 10 |
Elder supports all PyDAL-compatible databases. Below are configuration examples for each:
# Via components
DB_TYPE=postgres
DB_HOST=localhost
DB_PORT=5432
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=postgres://elder:password@localhost:5432/elderNote: PyDAL uses postgres:// not postgresql://
# Via components
DB_TYPE=mysql
DB_HOST=localhost
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=mysql://elder:password@localhost/elder?set_encoding=utf8mb4Automatically includes UTF8MB4 encoding for full Unicode support.
# Via components
DB_TYPE=sqlite
DB_NAME=elder # Creates elder.sqlite file
# Via URI
DATABASE_URL=sqlite://elder.sqliteNote: SQLite is file-based and doesn't require user/password/host.
# Modern SQL Server (2012+) - Recommended
DB_TYPE=mssql4
DB_HOST=localhost
DB_NAME=elder
DB_USER=sa
DB_PASSWORD=password
# SQL Server 2005+
DB_TYPE=mssql3
# ... same configuration
# Legacy SQL Server
DB_TYPE=mssql
# ... same configuration
# Via URI
DATABASE_URL=mssql4://sa:password@localhost/elder# Via components
DB_TYPE=oracle
DB_NAME=ORCL
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=oracle://elder/password@ORCLNote: Oracle uses a different URI format: user/password@database
# Via components
DB_TYPE=db2
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=db2://elder:password@elder# Via components
DB_TYPE=firebird
DB_HOST=localhost
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=firebird://elder:password@localhost/elder# Via components
DB_TYPE=ingres
DB_HOST=localhost
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=ingres://elder:password@localhost/elder# Via components
DB_TYPE=sybase
DB_HOST=localhost
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=sybase://elder:password@localhost/elder# Via components
DB_TYPE=informix
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=informix://elder:password@elder# Via components (uses DSN format)
DB_TYPE=teradata
DB_HOST=my_dsn
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=teradata://DSN=my_dsn;UID=elder;PWD=password;DATABASE=elder# Via components
DB_TYPE=cubrid
DB_HOST=localhost
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=cubrid://elder:password@localhost/elder# Via components
DB_TYPE=sapdb
DB_HOST=localhost
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=sapdb://elder:password@localhost/elder# Via components
DB_TYPE=mongodb
DB_HOST=localhost
DB_NAME=elder
DB_USER=elder
DB_PASSWORD=password
# Via URI
DATABASE_URL=mongodb://elder:password@localhost/elder# Via components
DB_TYPE=google:sql
DB_HOST=project-id:instance-name
DB_NAME=database
# Via URI
DATABASE_URL=google:sql://project-id:instance-name/databaseNote: DB_HOST should be in format project:instance
# Standard Datastore
DB_TYPE=google:datastore
DATABASE_URL=google:datastore
# With NDB API
DB_TYPE=google:datastore+ndb
DATABASE_URL=google:datastore+ndb# Via components
DB_TYPE=imap
DB_HOST=mail.example.com
DB_PORT=993
DB_USER=user@example.com
DB_PASSWORD=password
# Via URI
DATABASE_URL=imap://user@example.com:password@mail.example.com:993Note: Used for storing data in IMAP email folders (advanced use case).
Elder uses connection pooling to efficiently manage database connections:
DB_POOL_SIZE=10 # Number of connections in pool (default: 10)Recommendations:
- Development: 5-10 connections
- Production (small): 10-20 connections
- Production (large): 20-50 connections
- High traffic: 50-100 connections
Monitor your application's connection usage and adjust accordingly.
Example docker-compose.yml database configuration:
services:
api:
environment:
# Method 1: Full URI
- DATABASE_URL=postgres://elder:${DB_PASSWORD}@postgres:5432/elder
# Method 2: Individual components
- DB_TYPE=postgres
- DB_HOST=postgres
- DB_PORT=5432
- DB_NAME=elder
- DB_USER=elder
- DB_PASSWORD=${DB_PASSWORD}
- DB_POOL_SIZE=20
postgres:
image: postgres:16-alpine
environment:
- POSTGRES_DB=elder
- POSTGRES_USER=elder
- POSTGRES_PASSWORD=${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/dataElder uses PyDAL's automatic migration system:
PyDAL automatically creates and updates database tables based on model definitions:
# In shared/database/connection.py
db = DAL(
database_url,
migrate=True, # Enable automatic migrations
fake_migrate_all=False # Disable fake migrations
)Migration files are stored in the databases/ folder (or app.instance_path):
*.tablefiles - Table definitionssql.log- SQL migration history
Important: Keep these files in version control for production deployments.
For production environments where you want to control migrations:
db = DAL(
database_url,
migrate=False, # Disable migrations
fake_migrate_all=False
)Then manually apply schema changes as needed.
Elder defines 18 database tables in apps/api/models/pydal_models.py:
- organizations - Organization Units (OUs) hierarchy
- entities - Business entities (applications, services, etc.)
- dependencies - Entity dependency relationships
- identities - Users and service accounts
- identity_groups - User groups
- identity_group_memberships - Group membership
- roles - System roles
- permissions - Fine-grained permissions
- role_permissions - Role-to-permission mappings
- user_roles - User role assignments
- resource_roles - Resource-level RBAC
- issues - GitHub-style issue tracking
- issue_labels - Issue categorization
- issue_label_assignments - Issue-to-label mappings
- issue_comments - Issue discussion
- issue_entity_links - Entity-to-issue relationships
- metadata_fields - Typed metadata system
- audit_logs - Comprehensive audit trail
PyDAL automatically creates indexes for:
- Primary keys
- Foreign keys
- Fields marked with
unique=True
For additional indexes, define them in your table definitions:
Field('name', 'string', length=255, notnull=True),
Field('organization_id', 'reference organizations', notnull=True),
# Add custom index in PyDAL migrationUse PyDAL's query builder efficiently:
# Good: Specific field selection
rows = db(db.organizations.id > 0).select(
db.organizations.id,
db.organizations.name,
orderby=db.organizations.name,
limitby=(0, 100)
)
# Bad: Select all fields for large result sets
rows = db(db.organizations).select()Adjust DB_POOL_SIZE based on your workload:
# Low traffic
DB_POOL_SIZE=5
# Medium traffic
DB_POOL_SIZE=20
# High traffic
DB_POOL_SIZE=50Problem: Cannot connect to database
Solutions:
- Verify database is running:
docker-compose ps - Check connection string format matches your database type
- Verify credentials are correct
- Check network connectivity:
docker-compose exec api ping postgres
Problem: Migration fails or tables not created
Solutions:
- Check database permissions (user needs CREATE TABLE rights)
- Delete
databases/*.tablefiles and restart (development only!) - Check
databases/sql.logfor error messages - Verify database URL is correct
Problem: Slow database queries
Solutions:
- Increase
DB_POOL_SIZE - Add indexes to frequently queried columns
- Use
select()with specific fields instead ofselect(*) - Enable query logging to identify slow queries
- Consider read replicas for high-traffic applications
# Good
DB_PASSWORD=$(openssl rand -base64 32)
# Bad
DB_PASSWORD=password123Create a dedicated database user with minimal permissions:
-- PostgreSQL example
CREATE USER elder WITH PASSWORD 'strong_password';
GRANT CONNECT ON DATABASE elder TO elder;
GRANT USAGE ON SCHEMA public TO elder;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO elder;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO elder;For production, enable SSL connections:
# PostgreSQL with SSL
DATABASE_URL=postgres://user:pass@host/db?sslmode=require
# MySQL with SSL
DATABASE_URL=mysql://user:pass@host/db?ssl=trueUse secret management tools:
- AWS Secrets Manager
- HashiCorp Vault
- Kubernetes Secrets
- Docker Secrets
Use Docker networks to isolate database access:
services:
api:
networks:
- elder-network
postgres:
networks:
- elder-network
# No external port exposure in production!- PyDAL Documentation: https://py4web.com/_documentation/static/en/chapter-07.html
- Elder Database Models:
apps/api/models/pydal_models.py - Connection Code:
shared/database/connection.py - Docker Compose:
docker-compose.yml
For database-related issues:
- Check this documentation
- Review PyDAL documentation
- Check Elder logs:
docker-compose logs api - Open an issue on GitHub
Last Updated: 2025-10-25 PyDAL Version: 20251018.1 Supported Databases: 18+