Summary
If you are building or re-platforming a SaaS product on AWS in 2026 and you want PostgreSQL, you have three serious managed options: Amazon RDS for PostgreSQL, Amazon Aurora PostgreSQL (provisioned or serverless), and the newer Amazon Aurora DSQL, a serverless distributed SQL database that is PostgreSQL-compatible. They look similar in the console, but they behave very differently under load, on your invoice and in your application code.
The short version: RDS PostgreSQL is the sensible, predictable default for most early and mid-stage products. Aurora Serverless earns its keep when load is spiky or when you need fast failover, many read replicas or cross-Region disaster recovery. Aurora DSQL is the right tool for a narrower set of problems, mainly multi-Region active-active writes and truly idle-to-busy workloads, and it asks you to design your schema and transactions around its rules. This guide explains how to choose, what each option costs in practice, and how to wire each one into a Laravel or Node.js application.
The three options at a glance
Amazon RDS for PostgreSQL
RDS runs the standard open-source PostgreSQL engine on an instance you choose (for example a Graviton db.t4g or db.m7g class). AWS handles patching, automated backups, point-in-time recovery and Multi-AZ failover. Storage is EBS-based and you provision it, with autoscaling available. Because it is plain PostgreSQL, every extension on the RDS supported list, every ORM and every tool behaves exactly as it does on your laptop.
Amazon Aurora PostgreSQL (provisioned and serverless)
Aurora keeps the PostgreSQL query engine but replaces the storage layer with a distributed, self-healing volume replicated across three Availability Zones that grows automatically (up to 256 TB per the AWS documentation). Read replicas share that storage, so they add almost no replication lag and can be promoted quickly during a failover. You can run Aurora on provisioned instances, on Aurora Serverless capacity measured in Aurora Capacity Units (ACUs, roughly 2 GiB of memory each, billed per second), or mix both in one cluster. Aurora Serverless can now scale down to zero ACUs and pause when idle, which makes it far more attractive for staging and low-traffic tenants than it used to be.
Amazon Aurora DSQL
Aurora DSQL is not "Aurora with a switch flipped". It is a separate, serverless, distributed SQL database with no instances to size at all. Compute, commit and storage scale independently, you are billed for activity in Distributed Processing Units (DPUs) plus storage, and idle clusters cost nothing for compute. Multi-Region clusters are active-active with strong consistency, and AWS quotes up to 99.99% single-Region and 99.999% multi-Region availability. The trade-off is compatibility: DSQL speaks the PostgreSQL wire protocol and much of its SQL, but it does not support everything PostgreSQL does, and it uses optimistic concurrency control instead of row locks.
Side-by-side comparison
| RDS PostgreSQL | Aurora PostgreSQL / Serverless | Aurora DSQL | |
|---|---|---|---|
| Engine | Standard PostgreSQL | PostgreSQL engine on Aurora storage | PostgreSQL-compatible distributed SQL |
| Capacity model | Fixed instance size | Instances or ACUs that scale per second | No capacity to manage, billed per DPU |
| Scale to zero | No (you can stop an instance for up to 7 days) | Yes, serverless can pause at 0 ACU | Yes, by design |
| Extensions | Broad RDS-supported list (pgvector, PostGIS, pg_stat_statements…) | Similar broad list | Limited; check the compatibility page |
| Read scaling | Async read replicas | Up to 15 low-lag replicas on shared storage | Automatic |
| Multi-Region | Cross-Region read replicas | Global Database (one writer Region) | Active-active writes in multiple Regions |
| Concurrency | Standard PostgreSQL locking (MVCC) | Standard PostgreSQL locking (MVCC) | Optimistic; conflicting transactions fail at commit and must retry |
| Best fit | Most SaaS apps with steady load | Spiky load, high availability, many replicas | Global active-active apps, idle-heavy or bursty services |
What each option really costs
We deliberately avoid quoting dollar figures here, because AWS prices change by Region and over time. Use the official Aurora pricing page and the AWS Pricing Calculator with your own numbers. What matters more is the shape of each bill.
RDS: pay for the box, all month
You pay for the instance hours, provisioned storage, backup storage beyond the free allowance, and data transfer. Multi-AZ roughly doubles the instance cost because a standby runs all the time. The upside is predictability: if your traffic is steady, a right-sized Graviton instance with a one- or three-year Reserved Instance is usually the cheapest way to run PostgreSQL on AWS.
Aurora: storage and I/O matter as much as compute
With Aurora Standard you pay for compute, storage per GB-month and I/O requests. On write-heavy or scan-heavy workloads the I/O line can surprise you, which is why AWS offers Aurora I/O-Optimized: higher compute and storage prices, but no per-request I/O charges. A simple rule many teams use is to switch to I/O-Optimized once I/O is a large share of the Aurora bill (AWS suggests around a quarter). With Aurora Serverless, you also need a sensible minimum and maximum ACU range. Too high a minimum wastes money at night; too low a minimum means a cold buffer cache and slower first queries after a quiet period.
DSQL: pay for the work done
DSQL bills DPUs for compute, reads, writes and change data capture, plus storage. There is a monthly free tier (100,000 DPUs and 1 GB of storage at the time of writing). For a service that is idle most of the day, this model can be extremely cheap. For a database that is busy 24/7 with heavy analytical queries, model it carefully before committing, because every query is metered.
When RDS PostgreSQL is the right choice
- You are pre-product-market-fit or have under a few hundred thousand active users and steady, predictable load.
- You depend on specific extensions, such as
pgvectorfor embeddings,PostGISfor location data orpg_partmanfor partitioning. - Your team wants zero surprises: the same PostgreSQL version and behaviour in Docker locally, in CI and in production.
- Budget predictability matters more than elastic scaling.
For most of the Laravel and Node.js SaaS products we build, RDS PostgreSQL with Multi-AZ, automated backups, Performance Insights or Database Insights, and a read replica added later is the starting point. If you are still deciding between database engines, our PostgreSQL vs MySQL guide for SaaS covers that decision first.
When Aurora PostgreSQL or Aurora Serverless is worth it
- Spiky traffic: B2B dashboards busy 9-to-5 in one time zone, ticketing and events, marketing-driven peaks, end-of-month reporting.
- Faster failover and many replicas: Aurora replicas share storage, so promotion is quick and read scaling is simpler.
- Cross-Region disaster recovery: Aurora Global Database replicates to secondary Regions with typically sub-second lag and lets you promote a secondary if the primary Region fails.
- Large databases: storage grows automatically, so you stop worrying about disk sizing.
- Per-environment cost control: staging, QA and preview environments on Aurora Serverless that pause at zero overnight.
Aurora also lets you mix instance types in one cluster: a provisioned writer for steady baseline traffic and serverless readers that absorb reporting spikes. That hybrid pattern is often the best price-performance option for a growing SaaS.
When Aurora DSQL makes sense, and its catches
DSQL shines when you genuinely need writes accepted in more than one Region at the same time with strong consistency, for example a global payments ledger, inventory reserved by users on different continents, or a platform with strict uptime commitments. It is also attractive for new, bursty microservices that sit idle most of the time.
Before you choose it, check the current Aurora DSQL documentation for supported features. At launch, DSQL lacked several PostgreSQL features that ORMs and frameworks often assume, including foreign key constraints, triggers and most extensions, and it limits how much a single transaction can modify. AWS is expanding support, so verify against the latest list rather than older blog posts. The bigger design change is concurrency: DSQL uses optimistic concurrency control, so two transactions that touch the same rows do not wait on each other; one of them fails at commit and your code must retry it.
// Node.js: retry a DSQL transaction on optimistic-concurrency conflicts
async function withRetry(pool, work, attempts = 5) {
for (let i = 1; i <= attempts; i++) {
const client = await pool.connect();
try {
await client.query('BEGIN');
const result = await work(client);
await client.query('COMMIT');
return result;
} catch (err) {
await client.query('ROLLBACK').catch(() => {});
// SQLSTATE 40001 = serialization failure; check the DSQL docs for exact codes
if (err.code !== '40001' || i === attempts) throw err;
await new Promise(r => setTimeout(r, 2 ** i * 20 + Math.random() * 50));
} finally {
client.release();
}
}
}
DSQL also authenticates with short-lived IAM tokens rather than a static password, so your connection code needs to generate a token (the AWS SDK provides a signer) and refresh it before it expires.
Wiring it into Laravel
For RDS and Aurora, Laravel's standard pgsql driver works unchanged. With Aurora, point writes at the cluster endpoint and reads at the reader endpoint, and enable sticky so a request that just wrote data reads its own write:
// config/database.php
'pgsql' => [
'driver' => 'pgsql',
'read' => ['host' => [env('DB_READ_HOST')]], // Aurora reader endpoint
'write' => ['host' => [env('DB_WRITE_HOST')]], // Aurora cluster (writer) endpoint
'sticky' => true,
'port' => env('DB_PORT', 5432),
'database' => env('DB_DATABASE'),
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'sslmode' => 'require',
'options' => [PDO::ATTR_TIMEOUT => 5],
],
Three practical tips from production Laravel apps on AWS:
- Use RDS Proxy with Lambda or Laravel Vapor-style deployments, and with Octane workers that scale out quickly. Hundreds of short-lived connections can exhaust a small instance's
max_connections; a proxy pools them. - Expect a short pause after auto-pause. If Aurora Serverless pauses at zero ACUs, the first connection after a quiet period waits while it resumes. Keep production minimums above zero and use auto-pause for non-production environments.
- Queue workers and long reports should use the reader where they only read, so heavy exports do not slow down checkout or login on the writer.
Wiring it into Node.js
With pg, Prisma, Drizzle or TypeORM, RDS and Aurora are just PostgreSQL. Create two pools, one for the writer and one for the reader, and keep pool sizes modest because each Node.js process holds its own pool:
import pg from 'pg';
export const writer = new pg.Pool({
host: process.env.DB_WRITE_HOST, max: 10, ssl: { rejectUnauthorized: true },
idleTimeoutMillis: 30_000, connectionTimeoutMillis: 5_000,
});
export const reader = new pg.Pool({
host: process.env.DB_READ_HOST, max: 10, ssl: { rejectUnauthorized: true },
});
For DSQL, check that your ORM's migration tooling does not emit unsupported statements such as foreign keys or SERIAL columns; many teams switch to UUID primary keys and write migrations by hand for DSQL services.
A quick decision checklist
- Do you need active-active writes in more than one Region? If yes, evaluate Aurora DSQL first. If no, keep going.
- Does your app rely on extensions, foreign keys, triggers or long transactions? If yes, choose RDS or Aurora PostgreSQL.
- Is load steady most of the day? RDS with Reserved Instances is usually the cheapest.
- Is load spiky, or do you need fast failover and several replicas? Aurora, with serverless or a provisioned-plus-serverless mix.
- Do you have many idle non-production environments? Aurora Serverless with auto-pause, or DSQL for new services.
Whatever you choose, start with good fundamentals: indexes driven by real slow-query data, connection pooling, automated backups with tested restores, and alarms on CPU, memory, connections and replica lag. Choosing the "biggest" database rarely fixes a slow query.
Moving between them later
You are not locked in. Moving from RDS PostgreSQL to Aurora PostgreSQL is a well-trodden path: create an Aurora read replica of the RDS instance, let it catch up, then promote it during a short maintenance window. Moving into DSQL is a bigger job, because the schema and transaction handling may need changes, so treat it as a re-architecture of that service rather than a lift-and-shift. If your AWS bill is the real reason you are reconsidering, our cloud cost optimisation service reviews instance sizing, I/O configuration, reserved capacity and idle environments before any migration.
FAQ
Is Aurora faster than RDS PostgreSQL?
Often, for write-heavy and high-concurrency workloads, because of Aurora's distributed storage. For small or read-light apps the difference may not justify the higher baseline cost, so benchmark your own workload.
Can Aurora Serverless scale to zero?
Yes. Aurora Serverless can be configured with a minimum of 0 ACUs and pause when idle, then resume on the next connection after a short delay. It is ideal for development and staging environments.
Is Aurora DSQL a drop-in replacement for PostgreSQL?
No. It is PostgreSQL-compatible at the protocol and much of the SQL level, but some features are unsupported and it uses optimistic concurrency control, so applications usually need changes.
Which AWS PostgreSQL option is cheapest for a small SaaS?
For steady traffic, a small Graviton RDS PostgreSQL instance with a Reserved Instance is usually cheapest. For very low or intermittent traffic, Aurora Serverless with auto-pause or the Aurora DSQL free tier can cost less. Model it in the AWS Pricing Calculator.
Can I use pgvector for AI features on AWS?
Yes, on both RDS for PostgreSQL and Aurora PostgreSQL. Check the current Aurora DSQL documentation before planning vector search on DSQL.
Written by
Prakash Tank
Founder & Full-Stack Architect, DayDecoder
Prakash started as a certified Laravel developer and grew into a full-stack architect who owns a project end to end: requirements, architecture, development, deployment, and support. He designs event-driven systems with...
More about Prakash