StackPractices
beginner By Mathias Paulenko

AWS Basics — Core Services for Developers

A practical guide to AWS core services for developers: compute, storage, databases, networking, and security fundamentals with hands-on examples.

Overview

Amazon Web Services (AWS) is the most widely adopted cloud platform, with over 200 services — and that’s exactly the problem for newcomers. Nobody needs all 200. What you need is the working set that almost every production app is built on: compute, storage, a database, a network boundary, and identity. This guide covers that working set — EC2, Lambda, S3, EBS, RDS, DynamoDB, VPC, IAM — with the commands and gotchas you’ll hit in your first real deployment, and how the pieces fit together in an architecture you’d actually ship.

When to Use

Read this guide when:

  • You’re migrating a workload from on-premises to the cloud and need the map of what exists
  • You need growth-ready compute without managing hardware
  • You want managed databases and storage instead of self-hosted Postgres on a VM
  • You are building serverless or microservices architectures
  • You are setting up a new team’s AWS account and need the secure-by-default baseline

Skip it if you already know the core services and need depth on one — go straight to the service-specific recipe or guide instead.

Runnable versions of every command and snippet in this guide (CLI script, Lambda handler, IAM policy, DynamoDB example): companion resources. For the Azure equivalent, see Azure Basics — Core Services for Developers; for hands-on networking, the Terraform AWS VPC recipe builds the network layer described below.

Compute — EC2 and Lambda

EC2 (Elastic Compute Cloud)

Virtual servers in the cloud with full OS control.

# Launch an instance via CLI
aws ec2 run-instances \
  --image-id ami-0c55b159cbfafe1f0 \
  --count 1 \
  --instance-type t3.micro \
  --key-name my-key \
  --security-group-ids sg-123456 \
  --subnet-id subnet-123456
Instance FamilyUse Case
T3/T4gGeneral purpose, burstable (dev/test)
M6i/M6gGeneral purpose, sustained workloads
C6i/C6gCompute-intensive (APIs, batch)
R6i/R6gMemory-intensive (caches, analytics)

Pick the family by the bottleneck, not by name familiarity: T3 bursts and throttles under sustained load, M is the safe default, C for CPU-bound work, R when your working set doesn’t fit in RAM. Start one size smaller than you think you need — resizing later is a reboot, oversizing is a bill.

Lambda

Serverless functions that run in response to events. Pay per invocation and duration.

import json

def handler(event, context):
    return {
        'statusCode': 200,
        'body': json.dumps({'message': 'Hello from Lambda'})
    }

Lambda integrates with S3, API Gateway, SQS, SNS, DynamoDB streams, and CloudWatch Events.

Two limits shape real designs: functions cap at 15 minutes per invocation, and a cold start adds anywhere from ~100 ms (Python/Node) to several seconds (JVM) on the first request after idle. For user-facing endpoints that can’t tolerate cold starts, use provisioned concurrency — or accept that Lambda trades always-on cost for occasional latency.

Storage — S3 and EBS

S3 (Simple Storage Service)

Object storage for files, backups, static assets, and data lakes.

# Create a bucket
aws s3 mb s3://my-app-bucket

# Upload a file
aws s3 cp app.zip s3://my-app-bucket/builds/

# Make public (with caution)
aws s3api put-object-acl --bucket my-app-bucket --key app.zip --acl public-read
Storage ClassUse CaseRetrieval
StandardFrequently accessedImmediate
Intelligent-TieringUnknown access patternsImmediate
GlacierLong-term archivesMinutes to hours
Deep ArchiveCompliance backups12-48 hours

Storage classes are where the money hides. A lifecycle rule that moves objects to Intelligent-Tiering or Glacier after 30–90 days usually cuts S3 spend more than any other single change — and it costs you one JSON policy. Also note: you don’t pay for storage into S3, you pay for storage out — reads and cross-region egress add up faster than the storage itself.

EBS (Elastic Block Store)

Persistent block storage for EC2 instances. Like a virtual hard drive.

# Create and attach a volume
aws ec2 create-volume --size 100 --region us-east-1 --availability-zone us-east-1a --volume-type gp3
aws ec2 attach-volume --volume-id vol-12345 --instance-id i-12345 --device /dev/sdf

Use gp3 for almost everything — it’s cheaper than gp2 and lets you set IOPS and throughput independently of size. io2 is only worth it for databases that genuinely need >16k IOPS.

Databases — RDS and DynamoDB

RDS (Relational Database Service)

Managed PostgreSQL, MySQL, MariaDB, SQL Server, or Oracle.

# Create a PostgreSQL instance
aws rds create-db-instance \
  --db-instance-identifier mydb \
  --db-instance-class db.t3.micro \
  --engine postgres \
  --master-username admin \
  --manage-master-user-password \  # let RDS store it in Secrets Manager — never inline
  --allocated-storage 20

Two production switches to know before launch: MultiAZ gives you a synchronous standby for failover (costs ~2x, worth it for anything that matters), and read replicas offload reporting traffic — but replicas are asynchronous, so reads can lag writes by seconds.

DynamoDB

Managed NoSQL key-value and document database with single-digit millisecond latency.

import boto3

dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('Users')

table.put_item(Item={'id': 'user-1', 'name': 'Alice', 'email': 'alice@example.com'})
response = table.get_item(Key={'id': 'user-1'})

Choose on-demand billing until you’ve got months of traffic data — provisioned capacity only wins when your load is steady and predictable. And design your partition key first: a hot partition (one key absorbing most writes) throttles you no matter how much capacity you buy.

Networking — VPC

Virtual Private Cloud isolates your resources and controls traffic.

┌─────────────────────────────────────────────┐
│                    VPC                        │
│  ┌─────────────┐    ┌─────────────────────┐ │
│  │ Public Subnet│    │   Private Subnet    │ │
│  │  ┌───────┐  │    │  ┌───────┐ ┌─────┐ │ │
│  │  │  ALB  │  │    │  │  EC2  │ │ RDS │ │ │
│  │  └───┬───┘  │    │  └───┬───┘ └──┬──┘ │ │
│  │      │      │    │      │        │    │ │
│  │  Internet    │    │   NAT Gateway      │ │
│  │  Gateway     │    │   (egress only)    │ │
│  └──────────────┘    └────────────────────┘ │
└─────────────────────────────────────────────┘

Key components:

  • Subnets: Public (with IGW route) vs Private (no direct internet)
  • Security Groups: Stateful firewall at the instance level
  • NACLs: Stateless firewall at the subnet level
  • NAT Gateway: Allows private instances to reach the internet

Watch the NAT Gateway: it’s the classic surprise line item (~$0.045/GB processed on top of hourly). If private subnets only need AWS APIs, a VPC endpoint to S3 is free and avoids the NAT hop entirely.

Security — IAM

Identity and Access Management controls who can do what.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": "arn:aws:s3:::my-app-bucket/*",
      "Condition": {
        "StringEquals": {"aws:RequestedRegion": "us-east-1"}
      }
    }
  ]
}

The mental model: users are people, roles are identities services assume, and policies are the JSON documents that say what’s allowed. Your EC2 instance should assume a role with just the S3 permissions above — if the box is compromised, the attacker gets temporary credentials that expire, not a long-lived key sitting in a config file.

What works:

  • Use roles, not long-term access keys
  • Apply least privilege — grant the specific actions on the specific resources, then widen only when something breaks
  • Enable MFA for root and admin users
  • Use IAM policy conditions (aws:RequestedRegion, aws:SourceIp) for defense in depth

Observability — CloudWatch Basics

CloudWatch is where AWS surfaces what your resources are doing, and it’s half of every “why is this broken” answer:

  • Metrics are automatic per service: CPU on EC2, invocations and errors on Lambda, connections on RDS. Custom metrics (queue depth, business counters) go through the PutMetricData API or the CloudWatch agent on EC2.
  • Alarms turn metrics into pages. Two matter on day one: the billing alarm (AWS/Billing, us-east-1) and a CPU/error alarm per production resource.
  • Logs collect from Lambda (automatic), EC2 (agent), and app output. Set a retention period — the default is “keep forever,” which quietly bills you for logs nobody reads.
  • VPC Flow Logs record accepted/rejected traffic per network interface. Enable them when you create the VPC, not when you’re already debugging why the app can’t reach the database.
# Create a billing alarm — the first thing a new account needs
aws cloudwatch put-metric-alarm   --alarm-name billing-alert   --metric-name EstimatedCharges   --namespace AWS/Billing   --statistic Maximum --period 21600   --threshold 10 --comparison-operator GreaterThanThreshold   --dimensions Name=Currency,Value=USD   --alarm-actions arn:aws:sns:us-east-1:123456789012:billing-alerts

The alarm must be created in us-east-1 regardless of where your workload lives — AWS publishes billing metrics only there, which trips up everyone the first time.

Putting It Together: A Reference Architecture

A typical first production deployment on AWS looks like this:

Mermaid flowchart TD diagram

Client traffic hits the load balancer in public subnets. Compute — EC2 or Lambda — lives in private subnets with no direct internet exposure; it reaches out through the NAT Gateway when it must. The database sits in private subnets too, and S3 handles objects and static assets directly. IAM sits across everything, defining who (and which service) can touch what.

The two rules that make this shape work: nothing stateful goes in a public subnet, and every hop between tiers is controlled by security groups — the load balancer accepts traffic from anywhere, instances accept only from the load balancer’s security group, and the database accepts only from the instances’.

Choosing Between Services

The recurring question on AWS is rarely “does a service exist” — it’s which of three overlapping ones to pick:

NeedPickSkip
Long-running app with OS controlEC2Lambda (>15 min jobs, stateful)
Event-driven glue, spiky trafficLambdaEC2 (idle cost for idle work)
Containers you manageECSEKS unless you need Kubernetes APIs
Relational data, joins, transactionsRDSDynamoDB
Key-value, session data, high write scaleDynamoDBRDS
Shared file system across instancesEFSEBS (single instance only)

When two services overlap, the tiebreaker is operational burden: the more managed option is usually right for a small team, even if it costs more per unit. You’re buying back on-call hours, not compute.

EC2 vs Lambda

The default reasoning: if the work is an HTTP request that finishes in seconds, Lambda wins — no patching, no idle cost, scales to zero. If it’s a process that holds state (websockets, game servers), runs longer than 15 minutes, or needs predictable per-request latency under load, EC2 or a container wins. The hidden variable is team size: Lambda defers the ops burden to AWS, which matters more than raw pricing when three people own the platform.

RDS vs DynamoDB

Model your access patterns first. If the app needs joins, ad-hoc queries, or transactions across entities, it’s relational — use RDS. If you can describe reads as “get item by key” or “list items under one partition,” DynamoDB scales further and cheaper at high write volume. The mistake to avoid is picking DynamoDB for developer convenience and discovering six months later that your reporting needs SQL.

Common Architectures

Three shapes cover most of what a small team deploys first:

Static site / SPA hosting. S3 bucket (private) + CloudFront distribution in front + Route 53 for DNS. No servers at all: CloudFront serves from edge caches, S3 stores the build. This is the cheapest architecture AWS offers — cents per month at small scale — and it’s where the “serve from S3 directly” default goes wrong: keep the bucket private and let CloudFront be the only reader via origin access control.

Classic API backend. ALB → EC2/ECS in private subnets → RDS across two AZs, with S3 for uploads and ElastiCache if you need one. This is the diagram from the reference architecture section and it maps to 80% of CRUD backends. The pieces you forget at first: a health-check path that doesn’t hit the database, and connection draining so deploys don’t drop requests.

Event-driven pipeline. S3 upload → SQS queue → Lambda consumers → DynamoDB result table, with a dead-letter queue for the failures. No load balancer, no always-on compute — you pay per event and it scales to zero. This is the architecture to reach for when work is bursty or async (thumbnails, webhooks, imports).

A pattern worth noticing: in all three, the public surface is one managed thing (CloudFront, ALB, or S3 event) and everything else lives privately behind it. If your design has compute in a public subnet “temporarily,” that’s the bug to fix before launch.

Pricing Fundamentals

AWS pricing bites in three places that beginners underestimate:

Compute follows a menu: on-demand (no commitment, highest rate), Savings Plans or Reserved Instances (1–3 year commit, ~30–60% off), and Spot (up to ~90% off, can be reclaimed with two minutes’ notice). Spot is for stateless, interruptible work only.

Egress is the quiet killer: data in is free, data out to the internet costs ~$0.09/GB. Serving large files directly from EC2 instead of CloudFront, or replicating across regions casually, is how a $200/month app turns into $2,000.

The Free Tier is narrower than it looks: 750 hours/month of t2/t3.micro for 12 months, 5 GB S3, 1M Lambda requests — enough to learn, not enough to run production. Set a billing alarm (AWS/Billing metric in us-east-1 only) on day one, before you create anything else.

What Works

  1. Billing alarm before resources — a $10 threshold alarm in week one is cheaper than any architecture decision you’ll make later.
  2. Roles over keys — attach IAM roles to EC2/Lambda; never write an access key to disk or environment.
  3. Smallest viable instance — start one size down; CloudWatch will tell you when you’re wrong.
  4. Tag everything at creation — Service, Env, Owner tags are how finance and incident response stay sane six months in.
  5. One region until you need two — multi-region doubles cost and complexity; earn it with actual requirements, not fear.

Common Mistakes

Most AWS horror stories are self-inflicted and predictable — the same five mistakes, repeated in every new account. Security failures dominate (open buckets, root keys), followed by cost surprises (no alarms, forgotten instances) and silence where logs should be. Read this list before you deploy anything at all, not after the incident report lands.

  • Leaving S3 buckets public — use bucket policies and Block Public Access
  • Using root credentials — create IAM users and roles immediately
  • No VPC flow logs — you can’t debug what you can’t see
  • Oversized EC2 instances — start small and scale up; use CloudWatch metrics
  • Ignoring cost alerts — set up billing alarms before you get surprised
  • Picking the wrong region — data residency and latency are decided at account setup; moving regions later means migrating everything, and some services (like billing metrics in us-east-1) are region-pinned anyway
  • Manually managing infrastructure — anything you build by clicking in the console you will have to rebuild by memory; use Terraform or at least document every click
Mermaid flowchart LR diagram

Your First Week on AWS

A sane learning path, in order:

  • Day 1–2: secure the account. Root MFA on, an IAM admin role (not user) for yourself, billing alarm set, and a region picked — closest to your users.
  • Day 3–4: put a static site on S3 + CloudFront, then deploy one small app end-to-end: an EC2 instance in a private subnet behind a load balancer, talking to RDS. That single exercise exercises VPC, subnets, security groups, IAM, and EBS at once.
  • Day 5: break it on purpose — terminate the instance, watch what the load balancer reports, and rebuild it from your notes. If you can’t rebuild it, you didn’t learn it.
  • Day 6–7: automate the same deployment in Terraform, and write down what surprised you in Cost Explorer.

Resist the temptation to browse the service catalog — you learn AWS by shipping one small thing end-to-end, not by reading about 200 services.

Once that first deployment is stable, the natural next steps are the ones this guide’s neighbors cover: codify the whole architecture in Terraform so it’s reproducible and reviewable, put an auto-scaling policy around the compute tier so the load balancer’s job survives a traffic spike, and read a FinOps guide before the first real invoice arrives — AWS rewards the prepared and quietly bills everyone else.

Further Reading

Frequently Asked Questions

Is AWS free?

AWS offers a Free Tier: 12 months of limited usage on EC2, S3, RDS, and Lambda. Always monitor billing — "free tier" and "free" aren't the same thing.

Should I use ECS, EKS, or Lambda?
  • Lambda: event-driven, short-lived tasks
  • ECS: containerized workloads, AWS-native
  • EKS: Kubernetes-based workloads, multi-cloud portability
How do I secure secrets?

Use AWS Secrets Manager or Parameter Store (SSM). Never hardcode credentials in code or EC2 user data.

What's the difference between a region and an availability zone?

A region is a geographic cluster of AWS data centers (us-east-1, eu-west-1). An availability zone is an isolated data center inside a region — each region has 3+ AZs. Run production workloads across at least two AZs so a single data-center failure doesn't take you down.

How do I keep AWS costs under control?

Set a billing alarm first (the AWS/Billing metric lives only in us-east-1). Then tag resources by service and owner, turn on Cost Explorer, use Savings Plans once usage is steady, and watch egress — cross-region and internet-bound traffic is where surprise bills come from.

Where do I start with AWS?

IAM, S3, and billing alerts first — then deploy one small app end-to-end. Trying to learn all 200+ services at once is how people burn out; go deep on the handful this guide covers.