Multi-Database Support
FraiseQL supports multiple database backends, allowing you to use your preferred database while maintaining the same GraphQL API.
Supported Databases
Section titled “Supported Databases”| Database | Status | Best For |
|---|---|---|
| PostgreSQL | Primary | Production, full feature set |
| MySQL/MariaDB | Supported | MySQL-based infrastructure |
| SQLite | Supported | Development, embedded, testing |
| SQL Server | Supported | Enterprise Windows environments |
Configuration
Section titled “Configuration”PostgreSQL (Default)
Section titled “PostgreSQL (Default)”[database]type = "postgresql"url = "postgresql://user:password@localhost:5432/mydb"
[database.pool]min_connections = 5max_connections = 20idle_timeout_seconds = 300MySQL / MariaDB
Section titled “MySQL / MariaDB”[database]type = "mysql"url = "mysql://user:password@localhost:3306/mydb"
[database.pool]min_connections = 5max_connections = 20
[database.mysql]# Character setcharset = "utf8mb4"# Timezone handlingtimezone = "UTC"SQLite
Section titled “SQLite”[database]type = "sqlite"url = "sqlite:///path/to/database.db"
# Or in-memory for testing# url = "sqlite::memory:"
[database.sqlite]# Journal modejournal_mode = "wal"# Busy timeoutbusy_timeout_ms = 5000# Foreign keysforeign_keys = trueSQL Server
Section titled “SQL Server”[database]type = "sqlserver"url = "mssql://user:password@localhost:1433/mydb"
[database.sqlserver]# Trust server certificate (dev only)trust_server_certificate = false# Application nameapplication_name = "fraiseql"# Encrypt connectionencrypt = trueFeature Matrix
Section titled “Feature Matrix”| Feature | PostgreSQL | MySQL | SQLite | SQL Server |
|---|---|---|---|---|
| JSONB columns | Native | JSON type | JSON1 ext | NVARCHAR |
| UUID type | Native | CHAR(36) | TEXT | UNIQUEIDENTIFIER |
| Arrays | Native | JSON | JSON | JSON |
| Full-text search | Native | FULLTEXT | FTS5 | Full-text |
| Window functions | Full | Full | Limited | Full |
| CTEs | Recursive | Recursive | Recursive | Recursive |
| Subscriptions | LISTEN/NOTIFY | Polling | Polling | Polling |
| Connection pooling | Deadpool | Deadpool | Single | Deadpool |
Database-Specific Considerations
Section titled “Database-Specific Considerations”Full feature support, recommended for production:
-- Native JSONB with indexingCREATE TABLE tb_user ( pk_user BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, id UUID DEFAULT gen_random_uuid() UNIQUE, data JSONB NOT NULL);
-- GIN index for JSONBCREATE INDEX idx_user_data ON tb_user USING GIN (data);
-- Native array supportCREATE TABLE tb_post ( tags TEXT[] NOT NULL);Advantages:
- Native JSONB type with full indexing support
- GIN indexes for efficient JSON queries
- Native array types
- LISTEN/NOTIFY for subscriptions
JSON stored as JSON type:
-- JSON type (MySQL 5.7+)CREATE TABLE tb_user ( pk_user BIGINT AUTO_INCREMENT PRIMARY KEY, id CHAR(36) NOT NULL UNIQUE DEFAULT (UUID()), data JSON NOT NULL);
-- Generated column for indexingALTER TABLE tb_userADD COLUMN email VARCHAR(255) AS (JSON_UNQUOTE(data->>'$.email')) STORED,ADD INDEX idx_user_email (email);Notes:
- Use
JSON_UNQUOTE()for string extraction - Generated columns for indexed access to JSON fields
- UUID stored as CHAR(36)
- JSON functions:
JSON_OBJECT(),JSON_ARRAYAGG()
Lightweight, ideal for development:
-- JSON as TEXT with JSON1 extensionCREATE TABLE tb_user ( pk_user INTEGER PRIMARY KEY AUTOINCREMENT, id TEXT NOT NULL UNIQUE DEFAULT (lower(hex(randomblob(16)))), data TEXT NOT NULL CHECK (json_valid(data)));
-- Expression index for JSONCREATE INDEX idx_user_email ON tb_user (json_extract(data, '$.email'));Notes:
- Enable JSON1 extension
- UUID generated as hex string
- Single writer, multiple readers (WAL mode)
- JSON functions:
json_object(),json_group_array()
Enterprise Windows support:
-- NVARCHAR for JSON storageCREATE TABLE dbo.tb_user ( pk_user BIGINT IDENTITY(1,1) PRIMARY KEY, id UNIQUEIDENTIFIER NOT NULL UNIQUE DEFAULT NEWID(), data NVARCHAR(MAX) NOT NULL);
-- Computed column for indexingALTER TABLE dbo.tb_userADD email AS JSON_VALUE(data, '$.email');CREATE INDEX idx_user_email ON dbo.tb_user (email);Notes:
- JSON stored in NVARCHAR(MAX)
- Use
JSON_VALUE()andJSON_QUERY() - UNIQUEIDENTIFIER for UUIDs
- Use
FOR JSON PATHfor building JSON
Schema Adaptation
Section titled “Schema Adaptation”FraiseQL automatically adapts SQL generation per database:
WHERE Clause Generation
Section titled “WHERE Clause Generation”query { users(where: { email: { _eq: "user@example.com" } }) { id name }}SELECT * FROM v_user WHERE data->>'email' = 'user@example.com'SELECT * FROM v_user WHERE JSON_UNQUOTE(data->'$.email') = 'user@example.com'SELECT * FROM v_user WHERE json_extract(data, '$.email') = 'user@example.com'SELECT * FROM v_user WHERE JSON_VALUE(data, '$.email') = 'user@example.com'Migration Between Databases
Section titled “Migration Between Databases”Export Schema
Section titled “Export Schema”# Export for PostgreSQLfraiseql-cli generate-views --database postgresql -o postgres.sql
# Export for MySQLfraiseql-cli generate-views --database mysql -o mysql.sqlData Migration
Section titled “Data Migration”# Export data as JSONfraiseql-cli export --format jsonl > data.jsonl
# Import to new databasefraiseql-cli import --format jsonl < data.jsonlDevelopment Workflow
Section titled “Development Workflow”Local Development (SQLite)
Section titled “Local Development (SQLite)”[database]type = "sqlite"url = "sqlite:///dev.db"# Quick iterationfraiseql run --config dev.tomlTesting (SQLite In-Memory)
Section titled “Testing (SQLite In-Memory)”[database]type = "sqlite"url = "sqlite::memory:"Production (PostgreSQL)
Section titled “Production (PostgreSQL)”[database]type = "postgresql"url = "${DATABASE_URL}"
[database.pool]min_connections = 10max_connections = 50Connection Pooling
Section titled “Connection Pooling”PostgreSQL/MySQL/SQL Server
Section titled “PostgreSQL/MySQL/SQL Server”Uses Deadpool for async connection pooling:
[database.pool]min_connections = 5max_connections = 20connection_timeout_seconds = 30idle_timeout_seconds = 600max_lifetime_seconds = 1800SQLite
Section titled “SQLite”Single connection with WAL mode:
[database.sqlite]journal_mode = "wal"busy_timeout_ms = 5000cache_size = -64000 # 64MBPerformance Tuning
Section titled “Performance Tuning”PostgreSQL
Section titled “PostgreSQL”[database.postgresql]# Statement timeoutstatement_timeout_ms = 30000
# Prepared statementsprepare_threshold = 5
# Extra connection paramsoptions = "-c work_mem=256MB"[database.mysql]# Connection paramscharset = "utf8mb4"collation = "utf8mb4_unicode_ci"
# Performancemax_allowed_packet = "64M"SQLite
Section titled “SQLite”[database.sqlite]journal_mode = "wal"synchronous = "normal"cache_size = -64000mmap_size = 268435456 # 256MBTroubleshooting
Section titled “Troubleshooting”Connection Issues
Section titled “Connection Issues”# Test connectionfraiseql-cli test-connection --database "${DATABASE_URL}"Performance Problems
Section titled “Performance Problems”- Check connection pool settings
- Verify indexes on JSON fields
- Review query plans with
fraiseql-cli explain
Feature Compatibility
Section titled “Feature Compatibility”# Check database capabilitiesfraiseql-cli check-features --database "${DATABASE_URL}"Next Steps
Section titled “Next Steps”- Schema Design - Database-agnostic patterns
- Performance - Database optimization
- Deployment - Production database setup