Skip to main content

Overview

The kit uses two components for database management:
  • CloudNativePG - PostgreSQL operator for running databases in Kubernetes
  • Atlas - Schema migration tool that runs as a Kubernetes Job with Argo CD sync wave ordering
After Planetscale releases their updated terraform provider (Jan 2026)I plan to replace CloudNativePG with that as the recommended approach for hosting application databases.

Architecture

Argo CD sync waves ensure the migration Job completes before the application Deployment starts. The migration Job uses sync-wave: -1 (or lower) to run first.

CloudNativePG Clusters

View Existing Clusters

Create a New Cluster

Add a Cluster resource to your service’s Kubernetes manifests:

Access the Database

Connection Strings

CloudNativePG creates services for different access patterns: Connection string format:

Atlas Migrations

Migration File Structure

Migrations live in services/{service}/migrations/:

Create a New Migration

1

Write the migration SQL

Create a new file with timestamp prefix:
Write your migration:
2

Test locally

Run the migration against your local database:
3

Commit and deploy

The migration Job runs automatically before the application starts, ordered via Argo CD sync waves.

Migration Job

Migrations run as a Kubernetes Job before the application starts. Argo CD sync waves ensure proper ordering:

Atlas Configuration

Configure Atlas in atlas.hcl:

Common Operations

View Migration Status

Rollback a Migration

Atlas doesn’t support automatic rollbacks. To rollback:
  1. Create a new “down” migration that reverses the changes
  2. Deploy the rollback migration

Backup and Restore

CloudNativePG supports continuous backup to S3:
Trigger a backup:

Scale Replicas

Failover

CloudNativePG automatically handles failover. To manually promote a replica:

Troubleshooting

Migration job fails

  1. Check job logs:
  2. Common issues:
    • Database not ready (cluster still initializing)
    • Invalid SQL syntax
    • Missing permissions
  3. Retry the migration:

Database connection refused

  1. Check cluster status:
  2. Verify the service exists:
  3. Check pod readiness:

Cluster stuck in “Setting up primary”

  1. Check operator logs:
  2. Verify storage class exists:
  3. Check PVC status:

High latency queries

  1. Check connection pooling (consider PgBouncer)
  2. Review slow query logs:
  3. Add indexes via a new migration

Best Practices

  1. Always test migrations locally before deploying
  2. Make migrations idempotent when possible (IF NOT EXISTS, IF EXISTS)
  3. Avoid breaking changes - add columns as nullable, then backfill
  4. Use transactions for multi-statement migrations
  5. Back up before major changes in production
  6. Monitor replication lag with CloudNativePG metrics