Dev Mode¶
Use SQLite for local development and PostgreSQL in production with the same codebase.
What Is Dev Mode?¶
Dev mode lets you configure two database URLs:
- Production URL - Used by default
- Dev URL - Used when you pass --dev flag
database_config(
database_name="primary",
default=True,
database_type="postgresql",
database_url="postgresql://localhost/myapp", # Production
dev_database_type="sqlite",
dev_database_url="sqlite:///./dev.db", # Development
)
Run commands with --dev:
dbwarden --dev migrate # Uses SQLite
dbwarden --dev status # Uses SQLite
dbwarden migrate # Uses PostgreSQL
Why Use Dev Mode?¶
Speed¶
SQLite is much faster for local development: - No network latency - No authentication overhead - File-based, not server-based - Instant startup
Simplicity¶
No PostgreSQL server required: - No Docker setup - No installation - No configuration - Works on all platforms
Safety¶
Can't accidentally affect production:
- Dev database is a local file
- Each developer has their own database
- Easy to reset (rm dev.db)
- No shared state
Portability¶
Easy to share between developers: - One config file works everywhere - No server setup instructions - Fresh developers can start immediately
Basic Setup¶
Step 1: Configure Dev Database¶
# dbwarden.py
from dbwarden import database_config
database_config(
database_name="primary",
default=True,
database_type="postgresql",
database_url="postgresql://localhost/myapp",
dev_database_type="sqlite", # ← Add this
dev_database_url="sqlite:///./dev.db", # ← Add this
model_paths=["app.models"],
)
Step 2: Use Dev Mode¶
# Development workflow
dbwarden --dev make-migrations "create users"
dbwarden --dev migrate
dbwarden --dev status
# Production workflow
dbwarden make-migrations "create users"
dbwarden migrate
dbwarden status
Dev Mode Workflow¶
Daily Development¶
# Morning: pull latest code
git pull
# Run migrations against dev database
dbwarden --dev migrate
# Work on features...
# Add new models
# Generate migration
dbwarden --dev make-migrations "add orders table"
# Test migration
dbwarden --dev migrate
# Verify
dbwarden --dev status
# Commit
git add migrations/primary/0002_add_orders_table.sql
git commit -m "Add orders table"
Testing Rollbacks¶
# Apply migration
dbwarden --dev migrate
# Test rollback
dbwarden --dev rollback
# Re-apply
dbwarden --dev migrate
Fresh Start¶
Reset your dev database anytime:
# Delete dev database
rm dev.db
# Re-run migrations
dbwarden --dev migrate
Production Workflow¶
Dev mode only affects local development. Production uses the main URL:
CI/CD Pipeline¶
# .github/workflows/deploy.yml
- name: Run migrations
run: dbwarden migrate # No --dev flag
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
Production Deployment¶
# Staging
dbwarden migrate --database primary
# Production
dbwarden migrate --database primary
Dev mode is never used in CI/CD or production.
SQLite Limitations¶
What Works¶
Most features work in SQLite: - ✅ Tables, columns, indexes - ✅ Primary keys, foreign keys - ✅ Unique constraints - ✅ Basic data types - ✅ Transactions
What Doesn't Work¶
Some PostgreSQL features aren't available in SQLite: - ❌ Advanced types (JSONB, arrays, enums) - ❌ Partial indexes - ❌ Generated columns (in older SQLite) - ❌ Multiple schemas - ❌ Concurrent writes
Translation¶
DBWarden doesn't translate SQL between databases. Your migrations should work on both SQLite and PostgreSQL.
Approach 1: Write portable SQL
-- ✅ Works on both
CREATE TABLE users (
id INTEGER PRIMARY KEY,
email VARCHAR(255) NOT NULL
);
-- ❌ PostgreSQL-specific
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) NOT NULL,
metadata JSONB
);
Approach 2: Use PostgreSQL for dev too
database_config(
database_name="primary",
default=True,
database_type="postgresql",
database_url="postgresql://localhost/myapp",
dev_database_type="postgresql", # Same as prod
dev_database_url="postgresql://localhost/myapp_dev", # Different database
)
Environment-Based Configuration¶
Automatic Dev Mode¶
Use environment variables to automatically detect dev:
import os
is_dev = os.getenv("ENV", "dev") in ["dev", "development", "local"]
if is_dev:
database_url = "sqlite:///./dev.db"
database_type = "sqlite"
else:
database_url = os.getenv("DATABASE_URL")
database_type = "postgresql"
database_config(
database_name="primary",
default=True,
database_type=database_type,
database_url=database_url,
)
Run commands:
# Dev
ENV=dev dbwarden migrate
# Production
ENV=production dbwarden migrate
Multiple Dev Databases¶
If you have multiple databases, configure dev mode for each:
# Primary database
database_config(
database_name="primary",
default=True,
database_type="postgresql",
database_url="postgresql://localhost/main",
dev_database_type="sqlite",
dev_database_url="sqlite:///./dev_primary.db",
model_paths=["app.models.primary"],
)
# Analytics database
database_config(
database_name="analytics",
database_type="postgresql",
database_url="postgresql://localhost/analytics",
dev_database_type="sqlite",
dev_database_url="sqlite:///./dev_analytics.db",
model_paths=["app.models.analytics"],
)
Run against all dev databases:
dbwarden --dev migrate --all
dbwarden --dev status --all
Common Patterns¶
Pattern 1: SQLite for Dev, PostgreSQL for Prod (Recommended)¶
database_config(
database_name="primary",
default=True,
database_type="postgresql",
database_url="postgresql://localhost/myapp",
dev_database_type="sqlite",
dev_database_url="sqlite:///./dev.db",
)
Pros: - Fast local iteration - No server setup - Easy to reset
Cons: - SQL must be portable - Some features unavailable in dev
Pattern 2: PostgreSQL for Both¶
database_config(
database_name="primary",
default=True,
database_type="postgresql",
database_url="postgresql://prod-host/myapp",
dev_database_type="postgresql",
dev_database_url="postgresql://localhost/myapp_dev",
)
Pros: - Identical environments - Use all PostgreSQL features - Catches more bugs in dev
Cons: - Requires PostgreSQL server locally - Slower than SQLite
Pattern 3: Dynamic Based on Environment¶
import os
environment = os.getenv("ENV", "dev")
if environment == "production":
database_url = os.getenv("DATABASE_URL")
database_type = "postgresql"
elif environment == "staging":
database_url = os.getenv("STAGING_DATABASE_URL")
database_type = "postgresql"
else:
database_url = "sqlite:///./dev.db"
database_type = "sqlite"
database_config(
database_name="primary",
default=True,
database_type=database_type,
database_url=database_url,
)
Testing with Dev Mode¶
Unit Tests¶
Use SQLite for fast unit tests:
# tests/conftest.py
import pytest
from sqlalchemy import create_engine
from app.models import Base
@pytest.fixture(scope="function")
def db():
engine = create_engine("sqlite:///:memory:")
Base.metadata.create_all(engine)
yield engine
Base.metadata.drop_all(engine)
Integration Tests¶
Use --dev for integration tests:
# Run integration tests
dbwarden --dev migrate
pytest tests/integration/
Troubleshooting¶
"SQL syntax error in SQLite"¶
Cause: Using PostgreSQL-specific SQL.
Solution: Make SQL portable or use PostgreSQL for dev:
dev_database_type="postgresql"
dev_database_url="postgresql://localhost/myapp_dev"
"dev_database_url is required"¶
Cause: Set dev_database_type without dev_database_url.
Solution: Add both:
dev_database_type="sqlite"
dev_database_url="sqlite:///./dev.db" # ← Add this
Dev database not updating¶
Cause: Forgot --dev flag.
Solution: Use --dev:
dbwarden --dev migrate # ← Add --dev
Recap¶
You learned:
✅ What dev mode is and why it's useful
✅ How to configure dev and production URLs
✅ Daily development workflow with --dev
✅ SQLite limitations and workarounds
✅ Environment-based configuration
✅ Common patterns and best practices
✅ Testing strategies
✅ Troubleshooting dev mode issues
What's Next?¶
- Multi-Database - Multiple databases with dev mode
- Production Patterns - Deploy to production
- Troubleshooting - Common issues