Skip to content
Yeonuk Hwang
Go back

Journey to Serverless (Part 2): The Cost Crisis and Path to Change

Table of Contents

Open Table of Contents

1. Introduction

The system was running smoothly in production. The infrastructure was stable, the team was using it regularly, and operational costs were remarkably low at just $13/month. Everything seemed sustainable.

Then the AWS Free Tier window ended.

I had set up a budget alert months earlier specifically to catch this moment. When the alert triggered, I checked the projected costs and was surprised: once the free tier benefits expired, the monthly bill would jump from $13 to approximately $73/month.

The Business Context: While $73/month is trivial for most organisations, for an internal tool serving a small team within this company, it represented a significant operational expense that could be optimised. More importantly, even though I hadn’t signed a formal maintenance contract, I felt a professional responsibility to the client. Rather than simply present them with a higher bill, I decided to proactively investigate alternatives and present multiple options before costs escalated.

This decision—to take initiative and present solutions rather than just accept the increased costs—set the stage for what would become a complete architectural redesign.

2. The Cost Crisis: From $13 to $73

2.1. Understanding the Bill

When the free tier ended, costs jumped from $13 to $73. To understand the increase, I analysed the bill component by component.

Previous Cost Breakdown (Within Free Tier):

Projected Cost Breakdown (Post Free Tier):

2.2. The IPv4 Problem: The Unexpected Cost

I had expected the free tier to cover almost all costs, with only minor charges. However, I discovered an unexpected cost that completely changed the picture: IPv4 addresses.

The architecture required:

The Surprise: I had overlooked IPv4 address costs entirely. While AWS provides 1 free IPv4 address per account, the remaining three addresses (needed for EC2 and ALB) incurred charges even during the free tier period. What I didn’t realise at the time was that these IPv4 charges were actually the dominant cost factor—accounting for ~85% of the entire monthly bill during the free tier period.

The Architectural Trade-off: I had initially considered deploying to just one Availability Zone to reduce IPv4 costs, but ALB requires Multi-AZ deployment for reliability. I chose to deploy across all three AZs in the region, a choice that resulted in higher IPv4 charges than necessary for an internal tool with predictable, low-volume usage.

Hindsight: While all compute resources (EC2, RDS, ALB) stayed within free tier, the IPv4 charges alone added up quickly. If I had deployed to just two AZs instead of three, I could have saved approximately $3.50/month on IPv4 costs—a lesson I learned too late.

2.3. The Real Issue

The problem wasn’t the cost itself—it was permanence. The client’s priority was clear: minimise operational expenses. A $70/month recurring cost for an internal system with no direct revenue couldn’t be justified.

3. Three Options Evaluated

Using AWS Pricing Calculator, I evaluated three distinct approaches to reduce costs and prepared detailed cost projections for each option to present to the client.

3.1. Option 1: Savings Plans and Reserved Instances

Approach: Use AWS Savings Plans and Reserved Instances for long-term cost reduction.

Projected Monthly Cost: about $60/month (after 1 year commitments)

Evaluation:

Verdict: Better, but not good enough. Still too expensive.

3.2. Option 2: Single EC2 Instance with Embedded Database

Approach: Combine EC2 and RDS on a single instance, remove the ALB. Run both app and PostgreSQL in ECS.

Projected Monthly Cost: ~$18-22/month

Evaluation:

Verdict: Cost improves, but operational burden increases. The client has no dedicated developers, so this would lead to support issues. Savings don’t justify the added risk.

3.3. Option 3: Serverless Architecture

Approach: Migrate to Lambda and DynamoDB, paying only for actual usage.

Projected Cost: ~$5-10/month (85-90% reduction)

Evaluation:

Trade-offs Worth Considering:

Measured Cold Start Latency: ~2 seconds (API Gateway total latency during cold start), ~400ms after warm-up

For an internal tool, this is acceptable. Users don’t need sub-second responses, making this a reasonable trade-off for massive cost savings.

Development Effort: 2 months (backend rewrite, data migration, async redesign)

Verdict: Despite the development effort, the cost reduction, operational simplicity, and alignment with usage patterns make this the best choice.

4. The Decision: Why Serverless?

4.1. The Business Case

1. Cost Alignment: The Usage Pattern Perfect Match

The real insight wasn’t just that Serverless costs less—it was that this particular system’s usage pattern made Serverless dramatically more efficient.

The Usage Reality:

The Cost Implications:

For a 24/7 public-facing service, the distinction wouldn’t matter. But for an internal tool with concentrated usage in specific hours? Scale to Zero is transformative.

The system runs roughly 40 hours per week (business hours), idle the rest. Over a month, idle time exceeds 70%. Serverless charges only for active usage:

This 85% cost reduction directly reflected the system’s actual usage pattern, not theoretical savings.

2. Operational Burden

For a small team without dedicated ops staff, operational burden becomes the bigger constraint than cost.

4.2. The Client Decision

I presented all three options with detailed analysis and recommended Serverless:

The client chose Serverless.

4.3. Embracing the Challenge

The decision was rational: cost and operations both favoured Serverless. But implementation would be different.

The server-based system used familiar patterns—Node.js, PostgreSQL, relational models. Serverless required a complete shift:

Despite the unfamiliar patterns, this became the right architectural choice for the client’s actual constraints. I decided to embrace it as a genuine challenge.

5. The Path Forward

With approval secured, the next phase began: complete architectural redesign.

The new architecture needed to address:

The benefits were compelling:

In the next post, I’ll cover the technology choices and architectural decisions that transformed a $70/month system into a $5-10/month operation.

6. Key Takeaways

  1. Business context drives architecture: This was an internal tool for a small team with no dedicated developers. Low traffic, predictable usage, and operational burden made Serverless obvious. Match actual requirements, not theoretical ideals.

  2. Accept meaningful trade-offs: Trading slightly slower responses (2-second at worst when cold start) for 85% cost reduction, zero infrastructure management, and automatic high availability. For internal tools, this exchange is worthwhile.

The decision wasn’t just about cost—it was about matching reality: actual usage patterns, client constraints, and operational burden.


7. Next in the Series

Part 3: Technology Choices and Their Rationale examines the specific technology decisions made during the serverless migration:

Each decision prioritised cost efficiency whilst maintaining operational simplicity.


Series Navigation


Share this post:

Previous Post
Journey to Serverless (Part 3): Technology Choices and Their Rationale
Next Post
Journey to Serverless (Part 1): The Initial Server-Based Architecture