Amazon RDS & Aurora via SDK: Your First Database
Amazon RDS runs managed relational databases - PostgreSQL, MySQL, and more - so you get SQL without operating a server. Aurora is AWS's own high-performance engine in the same family.
Search across all documentation pages
Amazon RDS runs managed relational databases - PostgreSQL, MySQL, and more - so you get SQL without operating a server. Aurora is AWS's own high-performance engine in the same family.
The SDK's job here is provisioning: it creates the database and tells you where it lives. The actual queries go over a normal SQL driver, not the AWS SDK. This page does both halves.
Quick-reference recipe card - copy-paste ready.
# --- Python (boto3) ---
import boto3
rds = boto3.client("rds", region_name="us-east-1")
rds.create_db_instance(
DBInstanceIdentifier="first-db",
Engine="postgres",
DBInstanceClass="db.t3.micro",
AllocatedStorage=20,
MasterUsername="appuser",
MasterUserPassword="change-me-via-secrets-manager",
)
print("provisioning first-db")// --- TypeScript (AWS SDK v3) ---
import { RDSClient, CreateDBInstanceCommand } from "@aws-sdk/client-rds";
const rds = new RDSClient({ region: "us-east-1" });
await rds.send(new CreateDBInstanceCommand({
DBInstanceIdentifier: "first-db",
Engine: "postgres",
DBInstanceClass: "db.t3.micro",
AllocatedStorage: 20,
MasterUsername: "appuser",
MasterUserPassword: "change-me-via-secrets-manager",
}));
console.log("provisioning first-db");When to reach for this:
Create the instance, wait until it is available, read its endpoint, connect with a real SQL driver to run a query, then delete it.
# --- Python (boto3) ---
import boto3, psycopg2
rds = boto3.client("rds", region_name="us-east-1")
db_id, user, pwd = "first-db", "appuser", "change-me-via-secrets-manager"
# 1. Provision (control plane).
rds.create_db_instance(
DBInstanceIdentifier=db_id, Engine="postgres",
DBInstanceClass="db.t3.micro", AllocatedStorage=20,
MasterUsername=user, MasterUserPassword=pwd,
)
# 2. Wait until available (this takes several minutes).
rds.get_waiter("db_instance_available").wait(DBInstanceIdentifier=db_id)
# 3. Read the connection endpoint.
inst = rds.describe_db_instances(DBInstanceIdentifier=db_id)["DBInstances"][0]
host, port = inst["Endpoint"]["Address"], inst["Endpoint"]["Port"]
# 4. Connect with a normal SQL driver (data plane) - not the SDK.
conn = psycopg2.connect(host=host, port=port, user=user, password=pwd, dbname="postgres")
with conn.cursor() as cur:
cur.execute("SELECT version();")
print(cur.fetchone()[0])
conn.close()
# 5. Delete when done (skip the final snapshot for a throwaway db).
rds.delete_db_instance(DBInstanceIdentifier=db_id, SkipFinalSnapshot=True)// --- TypeScript (AWS SDK v3) ---
import {
RDSClient, CreateDBInstanceCommand, DescribeDBInstancesCommand,
DeleteDBInstanceCommand, waitUntilDBInstanceAvailable,
} from "@aws-sdk/client-rds";
import { Client } from "pg";
const rds = new RDSClient({ region: "us-east-1" });
const dbId = "first-db", user = "appuser", pwd = "change-me-via-secrets-manager";
// 1. Provision (control plane).
await rds.send(new CreateDBInstanceCommand({
DBInstanceIdentifier: dbId, Engine: "postgres",
DBInstanceClass: "db.t3.micro", AllocatedStorage: 20,
MasterUsername: user, MasterUserPassword: pwd,
}));
// 2. Wait until available (this takes several minutes).
await waitUntilDBInstanceAvailable({ client: rds, maxWaitTime: 1200 }, { DBInstanceIdentifier: dbId });
// 3. Read the connection endpoint.
const out = await rds.send(new DescribeDBInstancesCommand({ DBInstanceIdentifier: dbId }));
const ep = out.DBInstances![0].Endpoint!;
// 4. Connect with a normal SQL driver (data plane) - not the SDK.
const pg = new Client({ host: ep.Address, port: ep.Port, user, password: pwd, database: "postgres" });
await pg.connect();
const res = await pg.query("SELECT version();");
console.log(res.rows[0].version);
await pg.end();
// 5. Delete when done (skip the final snapshot for a throwaway db).
await rds.send(new DeleteDBInstanceCommand({ DBInstanceIdentifier: dbId, SkipFinalSnapshot: true }));What this demonstrates:
CreateDBInstance) and querying (psycopg2/pg) are two different planes with two different libraries.Address and Port) is what your SQL driver connects to.SkipFinalSnapshot=True deletes a throwaway database without a lingering snapshot.psycopg2 or pg - SELECT, INSERT, and the rest. The AWS SDK never runs SQL.Aurora is not a single instance but a cluster: a shared storage volume with one or more compute instances on top.
# --- Python (boto3) ---
import boto3
rds = boto3.client("rds", region_name="us-east-1")
rds.create_db_cluster(
DBClusterIdentifier="first-aurora",
Engine="aurora-postgresql",
MasterUsername="appuser",
MasterUserPassword="change-me-via-secrets-manager",
)
rds.create_db_instance( # add a compute instance to the cluster
DBInstanceIdentifier="first-aurora-1",
DBClusterIdentifier="first-aurora",
Engine="aurora-postgresql",
DBInstanceClass="db.r6g.large",
)// --- TypeScript (AWS SDK v3) ---
import { RDSClient, CreateDBClusterCommand, CreateDBInstanceCommand } from "@aws-sdk/client-rds";
const rds = new RDSClient({ region: "us-east-1" });
await rds.send(new CreateDBClusterCommand({
DBClusterIdentifier: "first-aurora",
Engine: "aurora-postgresql",
MasterUsername: "appuser",
MasterUserPassword: "change-me-via-secrets-manager",
}));
await rds.send(new CreateDBInstanceCommand({ // add a compute instance
DBInstanceIdentifier: "first-aurora-1",
DBClusterIdentifier: "first-aurora",
Engine: "aurora-postgresql",
DBInstanceClass: "db.r6g.large",
}));Aurora exposes separate reader and writer cluster endpoints, so you connect reads and writes to different hostnames for scale.
The examples inline a password for clarity, but do not do that. Let RDS manage a secret with ManageMasterUserPassword=True, which stores it in Secrets Manager, or enable IAM database authentication so the driver connects with a short-lived token instead of a static password.
CreateDBInstance returns while the database is still creating, with no usable endpoint. Fix: wait on db_instance_available first.ManageMasterUserPassword (Secrets Manager) or IAM database authentication.CreateDBCluster, then add cluster instances.SkipFinalSnapshot=True for throwaways and disable deletion protection first.| Alternative | Use When | Don't Use When |
|---|---|---|
| RDS instance (this page) | Standard managed relational database | You need Aurora's scale or serverless auto-scaling |
| Aurora (cluster) | High throughput, read replicas, storage auto-scaling | A tiny single-instance dev database |
| Aurora Serverless v2 | Spiky or unpredictable load with auto-scaling | Steady, predictable workloads where provisioned is cheaper |
| DynamoDB | Key-value/document access at scale, no SQL needed | You need joins, transactions, or ad-hoc queries |
| Self-managed DB on EC2 | Full control over the engine and host | You want AWS to handle patching, backups, and failover |
No. The SDK provisions and manages the database as a resource. Your SELECT and INSERT statements go through a normal SQL driver like psycopg2 or pg over the database connection.
From DescribeDBInstances. The Endpoint.Address is the host and Endpoint.Port is the port. Combine them with your master username and password in the SQL driver.
RDS provisions storage, boots the engine, and runs backups setup, which takes minutes. Read the endpoint only after the db_instance_available waiter returns.
Aurora separates storage from compute in a cluster. You call CreateDBCluster and then add compute instances, and you connect to separate reader and writer endpoints rather than one instance address.
Do not hardcode it. Use ManageMasterUserPassword to have RDS store it in Secrets Manager, or enable IAM database authentication so drivers use short-lived tokens.
Usually a network issue: the security group does not allow your app's traffic, or the instance is in a subnet your code cannot reach. Open the database port to the app's security group and check VPC routing.
By default DeleteDBInstance takes a final snapshot, which costs storage and slows deletion. SkipFinalSnapshot=True skips it - appropriate for throwaway databases, never for production.
No. Schema (CREATE TABLE) is data-plane SQL. Connect with your driver after provisioning and run the DDL there, or use a migration tool.
Choose RDS/Aurora when you need SQL, relationships, transactions, or ad-hoc queries. Choose DynamoDB when access patterns are known and you want predictable performance at scale.
Yes. A running instance bills for compute and storage whether or not it serves queries. Delete test databases, or use Aurora Serverless v2 to scale down during idle periods.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Reviewed by Chris St. John·Last updated Jul 24, 2026