Every developer I know has deployed to Vercel. Two clicks, a GitHub push, done. It's brilliant engineering — and for most use cases, the right call.
So why did I spend weeks wiring up VPCs, writing Terraform modules, configuring Security Groups, and debugging Route Tables at midnight?
Because I'm not building a side project. I'm building a proof.
The Honest Answer
When you're a self-taught developer trying to break into senior roles, credentials don't tell the full story. A portfolio deployed on Vercel tells a recruiter: "I know how to use a tool." A portfolio deployed on AWS with custom infrastructure tells them something different: "I understand what's happening underneath the tool."
The difference matters.
What I Actually Learned
Networking is not magic. Before this project, networking meant CSS classes to me. Now it means:
- A VPC carved into public subnets
- An Internet Gateway and Route Table that let EC2 talk to the world
- Security Groups acting as per-instance firewalls
- An Elastic IP so the server keeps the same address on every restart
Cost engineering is a discipline. AWS's Free Tier is generous, but the traps are subtle. A NAT Gateway costs around €32/month before any data transfer. I have zero NAT Gateways. A managed load balancer costs money too. Instead: Nginx on the same EC2, proxying both the Nuxt frontend and the Spring Boot API. Not the most scalable setup in the world. Perfectly fine for a portfolio. And it taught me exactly what an ALB does when you eventually need one.
Terraform makes infrastructure auditable. Every resource I have — EC2, DynamoDB, S3, Cognito, Lambda, SES — is described in .tf files. No clicking around the AWS console, no drift, no "I think I created that manually last month." The infrastructure is code, the code is in git, and git doesn't lie.
The Part Nobody Talks About
The hardest part wasn't the technology. It was the discipline of not over-engineering.
My first instinct was to add RDS for the blog. Then I remembered: DynamoDB with a single-table design handles my access patterns, costs nothing at this scale, and serverless means no instance to manage. My second instinct was to add a second EC2 for high availability. Then I remembered: I'm the only user. A t3.micro stopped when idle is the correct architecture here.
Senior engineering is knowing when not to add the thing.
The Stack
The result is a portfolio running on real infrastructure:
- Compute: t3.micro EC2 running Docker Compose (Nginx + Spring Boot)
- Frontend: Nuxt 4 with SSR and a SPA admin panel
- API: Spring Boot 3.5 with DDD layering
- Data: DynamoDB single-table design
- Events: S3 → Lambda (thumbnail processing), DynamoDB Streams → Lambda → SES (lead notifications)
- Auth: Cognito OAuth2 code flow
- IaC: Terraform managing everything
Not because I needed all of that. Because understanding all of that is the point.
Are we software engineers or plugin installers? The infrastructure is public — feel free to explore.