Deploying AWS Aurora: From Console Clicks to Production Infrastructure as Code
Introduction
If you've deployed databases on AWS, you've faced a choice: use standard RDS instances with their familiar but limited scaling, or embrace Aurora's cloud-native architecture with its promise of superior performance and availability. For years, Aurora remained somewhat of a black box—powerful but complex, with deployment methods ranging from manual console wizardry to sophisticated multi-cloud Infrastructure as Code.
The landscape has evolved dramatically. What once required deep AWS expertise and careful orchestration of DB clusters, subnet groups, parameter groups, and security policies can now be expressed as declarative configuration. But the path from "point and click in the console" to "production-ready IaC" is littered with anti-patterns, cost surprises, and availability pitfalls.
This document maps the Aurora deployment landscape—from the approaches you should avoid, through intermediate solutions, to production-grade practices. We'll explore how Aurora differs fundamentally from traditional RDS, why Infrastructure as Code matters more for databases than almost any other resource, and how Project Planton abstracts the complexity while preserving the power.
The Aurora Advantage: Why It's Not Just "RDS with Training Wheels"
Before diving into deployment methods, let's address the elephant in the room: when should you even use Aurora instead of standard RDS?
Aurora isn't simply a managed MySQL or PostgreSQL database. It's a complete reimagining of how relational databases work in the cloud. The key architectural difference is separation of storage and compute. In Aurora, all instances in a cluster share a single distributed storage volume that's automatically replicated six ways across three Availability Zones. This isn't just redundancy theater—it fundamentally changes the performance characteristics.
Traditional RDS instances use EBS volumes attached to each database server. If you create a read replica, AWS copies the entire dataset to a new EBS volume and replicates changes asynchronously. This means:
- Each replica adds storage cost (multiple copies of your data)
- Replica lag can be seconds or minutes under load
- Adding a replica takes time (full data copy)
- Failover requires promoting a replica and waiting for it to catch up
Aurora's shared storage means:
- Adding a read replica is nearly instant (just connects to existing storage)
- Replica lag is typically milliseconds (not seconds)
- You can have up to 15 replicas vs RDS's usual 5
- Failover happens in under 30 seconds, often 10-20 seconds
The performance claims you've heard—5x MySQL throughput, 3x PostgreSQL throughput—aren't marketing fluff. Aurora offloads crash recovery, buffer management, and replication to the storage layer, freeing the database instances to focus on query processing. For read-heavy workloads or applications that need near-zero-downtime failover, this is transformative.
When Aurora is the right choice:
- You need high read throughput with multiple replicas
- Application requires fast failover (sub-30 second RTO)
- You expect unpredictable growth (storage auto-scales to 128 TiB)
- Multi-region disaster recovery is a requirement (Global Database)
- You want to minimize operational overhead for replication and backups
When standard RDS might suffice:
- Small, predictable workloads where cost is paramount
- You need database engines Aurora doesn't support (Oracle, SQL Server, MariaDB)
- Specific engine features or versions not yet available in Aurora
- Legacy migrations where changing architecture isn't feasible
Aurora also introduces Serverless v2—a deployment mode where capacity scales automatically in fractions of a second. This isn't your grandfather's database autoscaling. Serverless v2 can handle production workloads with full multi-AZ support and read replicas, while scaling down to minimal capacity during low usage. It's fundamentally different from the original Serverless v1 (which could pause to zero but lacked HA and had slow cold starts).
The Deployment Maturity Spectrum
Let's walk through how teams typically deploy Aurora, from anti-patterns to production-ready solutions.
Level 0: The Anti-Pattern (Console Creation)
What it looks like:
A developer opens the AWS Console, navigates to RDS, selects "Create database," chooses Aurora MySQL, clicks through the wizard, types a password, and hits "Create." Twenty minutes later, they have a database.
What's wrong:
- No repeatability: Good luck recreating this exactly in another environment
- Secret exposure: That password you typed? It's in your shell history, maybe Slack logs
- Configuration drift: Changes made via console don't get tracked or versioned
- Security risks: Easy to accidentally enable public access or use weak security groups
- Single points of failure: Without careful AZ selection, you might create a single-instance "cluster"
The console is excellent for learning and experimentation. It's a terrible way to manage production databases. Yet we see this pattern repeatedly: "We'll just quickly spin up a database for this feature." Six months later, that "temporary" database is serving production traffic, and nobody knows exactly how it's configured.
The hidden costs:
Teams using console-based workflows eventually face an audit moment: "Document all our database configurations." Suddenly, someone is screenshotting console pages and maintaining a Word doc. When the inevitable "let's create a staging environment that matches prod" request comes, it's archaeology work trying to remember every checkbox.
Verdict: Acceptable for learning, sandbox environments, or true one-off experiments. Never for anything that matters.
Level 1: CLI Scripting (Imperative Automation)
What it looks like:
Engineers write shell scripts calling aws rds create-db-cluster and aws rds create-db-instance, maybe parameterized with environment variables. There's usually a deploy-aurora.sh that team members run from their laptops.
What this solves:
- Repeatability: The script can be run multiple times
- Documentation: The commands themselves document the configuration
- Parameterization: Different values for dev/staging/prod
What it doesn't solve:
- No state management: Script doesn't know if resources already exist
- Error handling complexity: Waiting for cluster to be available before creating instances requires custom logic
- Sequencing challenges: Must manually handle dependencies (subnet groups, parameter groups, etc.)
- Credential management: Still need to handle secrets securely (often fails)
- Drift detection: No way to know if someone changed something manually
The AWS CLI and SDKs (like Boto3) are powerful, but they're fundamentally imperative. Creating an Aurora cluster is a two-step process: first create the DB Cluster object, then add instances to it. Your script needs retry logic, waiter patterns, and error handling that infrastructure-as-code tools provide out of the box.
Real-world example:
A team builds a Python script using Boto3 to provision Aurora clusters. It works great until someone runs it twice accidentally—now there are duplicate resources or cryptic errors. Or worse, the script assumes certain AWS resources exist (VPC, subnets) and fails in new accounts. The script grows to hundreds of lines handling edge cases that Terraform or Pulumi handle automatically.
Verdict: Better than console for simple automation, but doesn't scale to complex environments. Useful for very specific orchestration tasks, but not as a primary deployment method.
Level 2: Configuration Management (Ansible, Chef)
What it looks like:
Using tools like Ansible with AWS modules to define Aurora clusters in playbooks. The amazon.aws.rds_cluster module describes the desired state, and Ansible attempts to reconcile it.
What this solves:
- Declarative-ish: Playbooks describe desired end state
- Idempotency: Can run playbooks multiple times (usually)
- Orchestration: Can combine database provisioning with application deployment
- Abstraction: Higher-level than raw CLI
Limitations:
- Database coverage incomplete: Not all Aurora features supported in modules
- State management weak: Ansible's state is "whatever AWS currently has," no local state file
- Provider lag: Modules updated slower than AWS adds features
- Not purpose-built for infrastructure: Ansible excels at configuration, less so at infrastructure provisioning
Historically, Ansible lacked full Aurora support, leading to hybrid approaches—using Ansible to run AWS CLI commands, which defeats the declarative purpose. Modern Ansible AWS collections have improved, but they're still playing catch-up.
Use case:
Ansible shines when you need to orchestrate database provisioning and configure applications that use it. For example: provision Aurora, create database schemas, deploy application code, configure DNS—all in one playbook. But for pure infrastructure, dedicated IaC tools are more powerful.
Verdict: Useful in mixed workflows (infra + config), but not the strongest choice for complex Aurora deployments.
Level 3: Infrastructure as Code (Terraform, Pulumi, OpenTofu)
What it looks like:
Aurora clusters defined in declarative configuration files (HCL for Terraform, code for Pulumi) that specify the desired state. Tools compare desired state with actual AWS state and apply changes.
Terraform/OpenTofu
Terraform is the most popular IaC tool for AWS infrastructure, including Aurora. A typical setup defines:
aws_rds_cluster(the cluster configuration)aws_rds_cluster_instance(writer and reader instances)aws_db_subnet_group(network configuration)aws_rds_cluster_parameter_group(engine settings)aws_security_group(network access rules)
Key advantages:
- State management: Terraform tracks infrastructure in a state file, enabling drift detection
- Plan workflow:
terraform planshows exactly what will change before applying - Module ecosystem: Community modules encapsulate best practices
- Multi-cloud: Same tool works for AWS, GCP, Azure
Production patterns:
- Remote state in S3 with DynamoDB locking (prevents concurrent modifications)
- Separate state files per environment (dev, staging, prod isolation)
- Module composition (reusable Aurora configurations)
- Lifecycle rules to prevent accidental deletion of production databases
What to watch for:
- Some Aurora changes (like engine version upgrades) can trigger replacement—use
lifecycleblocks carefully - State file contains sensitive information—must be encrypted
- Changing certain attributes (like
master_username) forces new resource creation
OpenTofu (the Terraform fork) is functionally equivalent—same HCL syntax, same providers. For open-source projects or organizations concerned about HashiCorp's license changes, OpenTofu provides a compatible alternative.
Pulumi
Pulumi takes a different approach: infrastructure defined in general-purpose programming languages (TypeScript, Python, Go). You use AWS SDK classes like aws.rds.Cluster and can leverage the full power of the language.
Key advantages:
- Familiar languages: Developers can use skills they already have
- Imperative logic: Easy to express conditional resources, loops, dynamic configurations
- ComponentResources: Build high-level abstractions (e.g., a
ProductionAuroraClustercomponent) - Type safety: Compile-time checks for configuration errors
Production patterns:
- Pulumi Cloud or self-hosted state backend (similar to Terraform)
- Policy as code (Pulumi CrossGuard for governance)
- Stack references for cross-stack dependencies
- Automation API for embedding infrastructure in applications
When Pulumi shines:
If your infrastructure has complex logic—say, dynamically creating read replicas based on external metrics, or integrating database provisioning tightly with application lifecycle—Pulumi's programming model makes this natural. For simpler declarative needs, Terraform's constraint is actually a feature (forces discipline).
The Comparison
| Aspect | Terraform/OpenTofu | Pulumi |
|---|---|---|
| Language | HCL (declarative DSL) | TypeScript, Python, Go, etc. |
| State | JSON state file (S3 + DynamoDB) | Pulumi Service or self-hosted |
| Ecosystem | Massive module registry | Growing, less mature |
| Learning curve | Moderate (learn HCL) | Lower (if you know the language) |
| Complex logic | Harder (HCL limited) | Natural (full programming) |
| Multi-cloud | Excellent | Excellent |
| Community | Very large | Growing |
For Aurora specifically:
Both tools handle the full Aurora feature set—Global Database, Serverless v2, custom parameter groups, encryption, monitoring. The choice often comes down to organizational preference. If you're already using Terraform for other infrastructure, consistency wins. If your team is primarily application developers who'd struggle with HCL, Pulumi reduces friction.
Best practices (either tool):
- Always use remote state with locking
- Manage secrets via AWS Secrets Manager, not hardcoded
- Use modules/components to encapsulate Aurora patterns
- Implement code review for infrastructure changes (treat IaC like application code)
- Test infrastructure changes in dev/staging before prod
Verdict: This is the production-ready approach. Terraform/OpenTofu for maximum community support and multi-cloud consistency. Pulumi when you need programming language power or your team prefers code over DSL.
Level 4: AWS-Native IaC (CloudFormation, CDK)
What it looks like:
Aurora defined in CloudFormation templates (JSON/YAML) or AWS CDK code (TypeScript, Python) that synthesizes to CloudFormation.
CloudFormation
AWS's native IaC service. Templates define AWS::RDS::DBCluster and AWS::RDS::DBInstance resources.
Advantages:
- AWS-managed state: No state file to manage; AWS tracks everything
- Tight integration: First-class support for new Aurora features (eventually)
- Rollback handling: Automatic rollback on stack failure
- Multi-account: StackSets for deploying across accounts
Limitations:
- Slower updates: New Aurora features lag behind API availability
- Verbose templates: YAML/JSON can be unwieldy for complex setups
- AWS-only: Can't manage multi-cloud infrastructure
When CloudFormation makes sense:
If your organization is all-in on AWS, uses AWS Organizations, and wants to avoid external tool dependencies, CloudFormation is a solid choice. It's particularly strong for compliance-focused environments where "AWS-native" is a requirement.
AWS CDK
CDK generates CloudFormation from code. High-level constructs like DatabaseCluster provide sensible defaults.
Advantages over raw CloudFormation:
- Less boilerplate: Constructs handle common patterns (e.g., auto-generating passwords in Secrets Manager)
- Code reuse: Build libraries of database patterns
- Type safety: Compile-time validation
- Default security: CDK constructs often enable encryption, deletion protection by default
Example value:
Creating an Aurora cluster with CDK might automatically set up encrypted storage, generate credentials in Secrets Manager, enable Performance Insights, and configure CloudWatch alarms—things you'd manually specify in CloudFormation or Terraform.
Limitation:
It's still CloudFormation under the hood. If CloudFormation doesn't support a feature yet, CDK can't use it either. For bleeding-edge Aurora capabilities, Terraform (which calls AWS APIs directly) sometimes has faster coverage.
Verdict: Strong choice for AWS-centric organizations. CDK provides better developer experience than raw CloudFormation. For multi-cloud or if you need latest features immediately, Terraform/Pulumi may be better.
Level 5: Higher-Level Abstractions (Crossplane, Platform Engineering)
What it looks like:
Aurora clusters represented as Kubernetes Custom Resources. Crossplane controllers reconcile these CRDs by provisioning actual AWS resources.
The Crossplane approach:
apiVersion: database.aws.crossplane.io/v1beta1
kind: DBCluster
metadata:
name: production-db
spec:
engine: aurora-postgresql
engineVersion: "14.6"
# ... configuration
A Crossplane controller watches this resource and creates the Aurora cluster in AWS, continuously reconciling desired vs actual state.
Advantages:
- GitOps friendly: Cluster definitions in Git, Kubernetes controllers apply them
- Multi-cloud abstraction: Same pattern for AWS, GCP, Azure databases
- Composition: Define high-level "Database" resources that provision Aurora + secrets + monitoring
- RBAC: Kubernetes-native access control
Challenges:
- Complexity: Requires Kubernetes control plane
- Provider lag: Crossplane AWS provider may not have all Aurora features immediately
- Learning curve: Need to understand both Kubernetes and AWS
When this makes sense:
For platform engineering teams building internal developer platforms on Kubernetes, Crossplane provides a consistent interface. Developers request a "database" and get Aurora (or Cloud SQL, or RDS) depending on context. The platform team maintains the compositions and policies.
For Project Planton's multi-cloud vision, this level of abstraction is interesting—but typically as an internal implementation detail, not what users interact with directly.
Verdict: Powerful for platform engineering at scale. Overkill for teams just needing to deploy Aurora. Best used when building a platform that abstracts cloud differences for application teams.
What Project Planton Supports (And Why)
Project Planton's philosophy is pragmatic abstraction: expose the 20% of configuration that 80% of users need, while making advanced options accessible for those who need them.
For Aurora, this means:
Default Approach: Pulumi-Backed Provisioned Clusters
Project Planton uses Pulumi under the hood to provision Aurora clusters. Why Pulumi over Terraform?
- Code as configuration: Easier to embed complex logic (like conditional read replicas, dynamic parameter groups)
- Type safety: Catch configuration errors at compile time
- Component model: Build reusable Aurora patterns (dev cluster, prod cluster, serverless cluster)
- Modern tooling: Better integration with CI/CD and policy enforcement
The protobuf API (AwsRdsClusterSpec) captures essential configuration:
- Engine:
aurora-mysqloraurora-postgresql - Instance configuration: Instance class or serverless scaling (min/max ACU)
- High availability: Subnet groups across multiple AZs, replica count
- Security: Encryption at rest (KMS), network isolation, IAM authentication
- Operational: Backup retention, maintenance windows, logging
What's Abstracted Away
You don't specify:
- Low-level parameter group details (unless you have custom requirements)
- Subnet group creation (derived from your VPC configuration)
- Security group minutiae (Project Planton creates appropriate rules)
You do get:
- Automatic secret management (master credentials in Secrets Manager)
- Deletion protection enabled by default in production
- CloudWatch log exports configured appropriately
- Performance Insights enabled with reasonable retention
Flexibility for Advanced Needs
The spec also exposes:
- Custom parameter groups: Override database engine settings when needed
- Serverless v2 configuration: Min/max ACU bounds for autoscaling
- Snapshot-based creation: Restore from existing snapshots
- Global database support: Create read replicas in other regions (via replication source)
The 80/20 Configuration Philosophy
Research shows most Aurora deployments configure:
- Engine and version
- Instance size (or serverless range)
- Number of replicas for HA
- Backup retention period
- Encryption (almost always enabled)
- Network placement (VPC, subnets)
Advanced configurations like Backtrack, multi-master, or custom engine modes are rarely used. Project Planton's spec focuses on the common cases while allowing advanced users to drop down to Pulumi/Terraform modules when needed.
Why Not CloudFormation?
CloudFormation is AWS-native and powerful, but Project Planton is a multi-cloud framework. Using Pulumi (or Terraform/OpenTofu) provides consistency across AWS, GCP, and Azure. You learn one approach to databases, not three different ones.
Example: Minimal Production Aurora Cluster
In Project Planton, defining a production Aurora cluster might look like:
apiVersion: aws.project-planton.org/v1
kind: AwsRdsCluster
metadata:
name: app-production-db
spec:
engine: aurora-postgresql
engineVersion: "14.7"
subnetIds:
- subnet-abc123 # private subnet AZ-a
- subnet-def456 # private subnet AZ-b
- subnet-ghi789 # private subnet AZ-c
databaseName: appdb
manageMasterUserPassword: true # use Secrets Manager
storageEncrypted: true
backupRetentionPeriod: 14 # two weeks PITR
enabledCloudwatchLogsExports:
- postgresql
iamDatabaseAuthenticationEnabled: true
deletionProtection: true
This minimal configuration gets you:
- Aurora Postgres 14.7 cluster
- Three subnets across three AZs (high availability)
- Credentials managed in AWS Secrets Manager
- Encrypted storage with AWS-managed KMS key
- Two-week backup retention
- PostgreSQL logs exported to CloudWatch
- IAM database authentication available
- Protection against accidental deletion
Project Planton fills in the rest: security groups allowing your application, appropriate instance classes based on environment (dev vs prod), Performance Insights enabled, etc.
For serverless:
spec:
engine: aurora-mysql
serverlessV2Scaling:
minCapacity: 0.5
maxCapacity: 8
# ... other config
This creates a Serverless v2 cluster that scales from 0.5 ACU (very low cost when idle) up to 8 ACUs (roughly equivalent to a large instance) under load.
Production Essentials: What You Must Get Right
Regardless of deployment method, certain Aurora configurations are non-negotiable for production.
High Availability
Minimum: One writer and one reader in separate Availability Zones.
Aurora's storage is replicated across 3 AZs automatically, but if your single writer instance fails, the cluster must fail over to a reader. With no reader, Aurora will restart the writer (slower, potential data loss window).
Best practice:
- At least two instances (writer + reader) in different AZs
- For mission-critical: three instances across three AZs
- Set failover priority tiers (promote specific replica first)
- Use cluster endpoint for writes, reader endpoint for reads
Serverless v2 HA:
Serverless v2 supports multi-AZ. Create at least one serverless reader in another AZ for high availability.
Encryption
Storage encryption must be enabled at cluster creation. You cannot encrypt an existing unencrypted cluster—it requires snapshot, restore to encrypted.
Best practice:
- Always enable
storageEncrypted: true - Use customer-managed KMS key for compliance scenarios (allows key rotation control)
- Enable SSL/TLS for connections (set
rds.force_sslparameter) - Store credentials in AWS Secrets Manager, never in code
Backup and Recovery
Automated backups: Aurora performs continuous backups with point-in-time recovery.
Best practice:
- Set
backupRetentionPeriodto at least 7 days (14+ for critical systems) - Use
copyTagsToSnapshot: trueto maintain metadata - Schedule manual snapshots before major changes
- Test recovery process periodically (restore to new cluster, verify data)
Cross-region disaster recovery:
For true DR, use Aurora Global Database (replicates to another region with <1 second lag). Regular snapshots can be copied to other regions as a cheaper alternative.
Monitoring
Essential monitoring:
- CloudWatch alarms on CPU, memory, connections, replica lag
- Enable Performance Insights (identifies slow queries, wait events)
- Export logs to CloudWatch (error logs, slow query logs)
- Consider Enhanced Monitoring for OS-level metrics
Anti-pattern:
Setting up monitoring and then ignoring it. Ensure your on-call team actually responds to alarms and has runbooks for common issues.
Network Security
Best practice:
- Aurora instances in private subnets only (no public access)
- Security groups allowing only application servers
- Use VPC endpoints or VPN for administrative access, not public IPs
- If cross-account access needed, use VPC peering or Transit Gateway
Anti-pattern:
Making Aurora publicly accessible for "easier access during development." This is how production databases get compromised.
Parameter Tuning (Sparingly)
Most Aurora defaults are well-tuned. Common customizations:
max_connectionsif default is too low (but consider connection pooling instead)slow_query_logandlong_query_timefor query monitoring- Timezone settings if required
- SSL enforcement (
require_secure_transport)
Anti-pattern:
Randomly tweaking parameters hoping for better performance. Profile queries first, optimize schema and indexes, scale instance size—then consider parameter changes.
Cost Management
Aurora's pricing model (instance hours + storage + I/O) can surprise teams.
Best practices:
- Monitor I/O costs; if >25% of bill, consider Aurora I/O-Optimized
- Use Reserved Instances for stable workloads (30-60% savings)
- For variable workloads, Serverless v2 can reduce costs
- Stop/scale down dev/staging environments when not in use
- Set CloudWatch alarms on estimated charges
Serverless v2 cost consideration:
Serverless v2 doesn't pause to zero—minimum capacity always runs. For truly intermittent dev workloads, might be cheaper to stop a provisioned cluster. For spiky prod workloads, serverless avoids paying for peak capacity 24/7.
Common Anti-Patterns (And How to Avoid Them)
Anti-Pattern: Manual Secret Management
What it looks like:
Hardcoding database passwords in environment variables, config files, or worse—committed to Git.
Why it's wrong:
Credentials leak via logs, CI/CD output, shared config. Rotation is manual and error-prone.
The fix:
Use AWS Secrets Manager. Set manageMasterUserPassword: true in your cluster spec. Application retrieves credentials at runtime. Enable automatic rotation for non-IAM auth scenarios.
Anti-Pattern: Single-AZ Deployment
What it looks like:
Aurora cluster with only one instance, or all instances in one AZ to "save costs on cross-AZ traffic."
Why it's wrong:
No protection against AZ outages. If the single instance fails, extended downtime while Aurora restarts it. Cross-AZ traffic costs are negligible compared to downtime costs.
The fix:
Minimum two instances in separate AZs. The slight cross-AZ data transfer cost ($0.01/GB) is insurance against outages.
Anti-Pattern: Ignoring Backups
What it looks like:
backupRetentionPeriod: 1 (or even 0) to "reduce storage costs."
Why it's wrong:
First major data issue (accidental deletion, corrupt data load) and you're restoring from nothing or stale backup.
The fix:
At least 7 days retention. AWS gives you backup storage equal to your database size for free. Extended retention beyond that is cheap insurance.
Anti-Pattern: Using Master User for Applications
What it looks like:
Application connects with the cluster's master admin user for all operations.
Why it's wrong:
If application is compromised, attacker has full database access. Accidentally drop a table? No isolation.
The fix:
Create application-specific database users with minimal necessary privileges. Use IAM database authentication to avoid managing additional passwords.
Anti-Pattern: No Deletion Protection
What it looks like:
deletionProtection: false because "it's annoying during testing."
Why it's wrong:
Fat-fingered terraform destroy or AWS console click deletes production database.
The fix:
Enable deletion protection in production. Slightly annoying to disable it when you actually want to delete the cluster, but that's the point—deliberate friction for destructive operations.
Anti-Pattern: Defaulting to Largest Instances
What it looks like:
"We'll just use db.r6g.16xlarge to be safe."
Why it's wrong:
Massive overprovisioning wastes money. Aurora scales well—start smaller, monitor, scale up if needed.
The fix:
Right-size based on actual workload. Use CloudWatch metrics (CPU, memory, connections) to inform decisions. For unpredictable workloads, Serverless v2 auto-scales.
Aurora Serverless v2: When Autoscaling Makes Sense
Aurora Serverless v2 deserves special attention because it changes the scaling model fundamentally.
Serverless v1 (legacy):
- Could pause to zero (cost savings for intermittent workloads)
- Slow scaling (30+ seconds to add capacity)
- No high availability (single instance, no replicas)
- Cold start latency when resuming from pause
Serverless v2 (current):
- Scales in fractions of a second, increments of 0.5 ACU
- Supports multi-AZ and read replicas (full HA)
- No pause feature (minimum capacity always running)
- Participates in cluster like any provisioned instance
When to use Serverless v2:
- Development/staging environments: Scale down to 0.5 ACU overnight, scale up during testing
- Unpredictable traffic patterns: Applications with highly variable load (think B2B SaaS where usage spikes during business hours)
- Batch workloads: Normally idle, but needs significant capacity for ETL jobs
- Multi-tenant SaaS: Different tenants have different peak times; serverless adapts
When provisioned is better:
- Steady high load: If consistently using 8+ ACUs, provisioned instance with Reserved Instance pricing is cheaper
- Latency-sensitive: Serverless scaling is fast but not instantaneous; provisioned is fixed capacity
- Budget predictability: Provisioned instances have fixed costs; serverless varies with usage
Cost comparison example:
- Provisioned
db.r6g.large: ~$0.25/hour on-demand (~$180/month), less with RI - Serverless v2 at 2 ACUs: 2 × $0.12 = $0.24/hour (~$173/month)
- Serverless v2 at 0.5 ACU (off-hours): 0.5 × $0.12 = $0.06/hour
If your average usage is low but with spikes, serverless wins. If steady load, provisioned (especially reserved) is cheaper.
Aurora MySQL vs PostgreSQL: Choosing Your Engine
Both Aurora MySQL and Aurora PostgreSQL share the same underlying storage architecture, but differ in features and use cases.
Aurora MySQL
Unique features:
- Backtrack: Rewind database to previous point in time without restoring from backup (seconds vs hours)
- Parallel Query: Offload query processing to storage layer for faster scans (analytics workloads)
- MySQL-specific optimizations (InnoDB improvements, etc.)
Best for:
- Applications already using MySQL (easy migration)
- Workloads that benefit from Backtrack (fast "undo" for mistakes)
- Analytics queries on large datasets (Parallel Query)
Aurora PostgreSQL
Unique features:
- Babelfish: SQL Server compatibility layer (migrate from SQL Server)
- PostgreSQL extensions (PostGIS, etc.)
- Advanced SQL features (CTEs, window functions, JSONB)
Best for:
- Applications already using PostgreSQL
- Complex queries leveraging advanced SQL
- Geospatial workloads (PostGIS)
- Teams migrating from SQL Server (via Babelfish)
Performance Differences
AWS claims Aurora MySQL delivers 5x MySQL throughput, Aurora PostgreSQL 3x PostgreSQL throughput. In practice:
- Aurora MySQL often has slight edge in high-concurrency OLTP
- Aurora PostgreSQL excels in complex queries and JSON workloads
For most applications, the choice is driven by existing ecosystem (MySQL-based app uses Aurora MySQL, PostgreSQL-based uses Aurora PostgreSQL). Both engines get Aurora's benefits (fast failover, shared storage, read scaling).
Conclusion
The journey from "clicking around in the AWS Console" to production-ready Aurora deployments is really a journey from hope-driven infrastructure to confidence-driven infrastructure.
Hope-driven: "I hope this configuration is secure." "I hope we can recreate this in disaster recovery." "I hope the password is saved somewhere."
Confidence-driven: "Our infrastructure is versioned in Git. We've tested failover. Credentials are managed by Secrets Manager with automatic rotation. We have point-in-time recovery for two weeks. CloudWatch alarms notify us of anomalies. Everything is encrypted."
Infrastructure as Code—whether Terraform, Pulumi, CloudFormation, or Crossplane—is the foundation of that confidence. It transforms Aurora deployment from art (requiring deep AWS expertise and careful console navigation) to engineering (declarative, reviewable, testable configuration).
Project Planton's approach is to meet you where production infrastructure should be: sensible defaults, essential security baked in, and the flexibility to customize when your needs demand it. You're not clicking checkboxes in a wizard. You're declaring intent in protobuf, and infrastructure emerges, repeatable and auditable.
Aurora's promise—cloud-native performance, automatic scaling, near-zero-downtime failover—is real. But it's only realized when deployed with discipline. Use Infrastructure as Code. Enable encryption and deletion protection. Deploy multi-AZ. Monitor proactively. Manage secrets properly. Do these things, and Aurora becomes what it was designed to be: a database that gets out of your way so you can focus on your application.
The landscape has evolved. The tooling is mature. The anti-patterns are well-documented. There's no longer an excuse for hope-driven database infrastructure. The path to production-ready Aurora is clear—now walk it.
Next article