Official guide to launching and connecting to an RDS database instance. Read →
Running PostgreSQL on EC2 means you're responsible for: backups, patching, failover, replication, monitoring disk usage. RDS automates all of this.
| Feature | Self-managed on EC2 | AWS RDS |
|---|---|---|
| Automated backups | You configure | Automatic, point-in-time recovery |
| Multi-AZ failover | Complex setup | One checkbox |
| OS patching | Your responsibility | Managed by AWS |
| Read replicas | Configure manually | One-click |
| Cost | Cheaper | ~2-3x more than self-managed |
# Via AWS Console: RDS → Create database
# Key settings:
# - Engine: PostgreSQL 16
# - Template: Free tier (db.t3.micro)
# - DB identifier: myapp-db
# - Master username: adminuser
# - Password: generate a strong password
# - VPC: same VPC as your EC2 instance
# - Subnet group: private subnets (no public access!)
# - Security group: allow port 5432 FROM your EC2 security group only
# - Backup: 7 days retention
# - Deletion protection: enable for production
# Never put RDS in a public subnet in production
# Your EC2 connects internally via the private endpoint
RDS should only be accessible from within your VPC. If you enable "Publicly Accessible", you're exposing your database to the internet. Always use private subnets and security groups to restrict access.
# Store your database credentials in Secrets Manager
aws secretsmanager create-secret --name "myapp/database" --secret-string '{
"username": "adminuser",
"password": "super-secret-password",
"host": "myapp-db.cluster-xxx.us-east-1.rds.amazonaws.com",
"port": 5432,
"dbname": "myapp"
}'
# Retrieve in Node.js using AWS SDK
import { SecretsManagerClient, GetSecretValueCommand } from "@aws-sdk/client-secrets-manager";
const client = new SecretsManagerClient({ region: "us-east-1" });
const response = await client.send(
new GetSecretValueCommand({ SecretId: "myapp/database" })
);
const secret = JSON.parse(response.SecretString);
const databaseUrl = `postgres://${secret.username}:${secret.password}@${secret.host}/${secret.dbname}`;
Use Secrets Manager for credentials (it auto-rotates). Use SSM Parameter Store for non-secret config values — it's cheaper.