Technical
Serverless Lessons from a Year of AWS Free Tier Production Apps
I ran multiple production apps on AWS free tier for a full year. Total infrastructure bill: under $20. The apps served real traffic, sent real emails, and stored real data. Here is what a year on the cheapest possible stack actually taught me.
The Stack That Stayed Free
- Lambda: all compute
- DynamoDB: all persistent data
- SES: all transactional email
- S3: all static assets
- EventBridge: all scheduled jobs
- CloudWatch: all logs and metrics
Six services. No EC2. No RDS. No load balancer. The bill stayed tiny because I stayed serverless.
What I Learned About Cold Starts
Cold starts sounded scary in the blog posts. In production they were a non-event. My Lambda functions cold-start in under 400ms. Users do not notice. Warm invocations are under 50ms.
# Keep handlers tiny, init heavy clients at module level
import boto3
# Global: reused across invocations
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('posts')
def handler(event, context):
# Handler does one thing
return table.get_item(Key={'id': event['id']})The DynamoDB Surprise
DynamoDB is not a relational database and pretending it is will hurt you. I spent the first month trying to write SQL patterns. The moment I embraced single-table design and access-pattern-first modeling, everything clicked. The free tier held 25GB of real production data without issue.
What I Would Change
Two things I got wrong early:
- Deployment pipeline: I hand-deployed for too long. SAM or Serverless Framework pays back fast.
- Observability: default CloudWatch logs are not enough. Add structured logging from day one.
The Real Free-Tier Lesson
The free tier is not a trick or a trap. It is a genuine invitation to build things that stay small forever. Most side projects never exceed the free tier. Most client MVPs do not either. Start free, stay free, only pay when traffic forces it.
The Mental Model Shift
Serverless is not cheap hosting. It is a different way to think about applications. Every Lambda is a function, not a service. Every request is independent. Every piece of state lives elsewhere. The mental model took me a full quarter to internalize. Once it clicked, I stopped fighting the platform and started building with it.
The Parts I Still Do Not Use
- Step Functions (EventBridge covered my orchestration needs)
- AppSync (REST from FastAPI was simpler)
- Cognito (custom JWT flow was easier to reason about)
Not every AWS service earned a spot in the stack. The ones that did pulled their weight for a full year.
For the current free-tier limits, see the AWS Free Tier page.
RELATED READING
The Consulting Shift I Am Making In Year Two
After a year of writing and building, my consulting practice is changing shape. Shorter engagements. Sharper outcomes.
ReadThe Frontend Shift: Shipping Less JavaScript In Year Two
A year ago I reached for Next.js for everything. This year I often reach for nothing.
ReadThe Serverless Lesson I Would Write On A Sticky Note
After a year of shipping serverless projects, one rule explains most of the wins and all of the losses.
Read