Building scalable, resilient applications often brings to mind concerns about performance, features, and user experience, but cost considerations are rarely treated as a first class design principle. Even the field of FinOps, which focuses on managing cloud costs, tends to take a reactive approach, aiming to rein in inefficiencies and reduce excessive waste in systems that were not designed with affordability in mind. While this can help curb out of control expenses, it often comes at a significant labor and opportunity cost, as optimization efforts compete with feature development and other business priorities. Moreover, it typically results in systems that are merely right sized, rather than fundamentally cost efficient or affordable at scale.

By contrast, designing with affordability in mind from the start can lead to systems that not only scale effectively, remain sustainable in the long term, and create a competitive advantage by enabling greater flexibility in pricing, experimentation, and resource allocation. This approach was central to the architecture of BestSelfApp, a personal tracking app I launched this past October. In its first three months, the app served 858 users, who performed a total of 24,409 actions in the mobile app. This activity led to 146,000 API requests, 452,000 Lambda invocations, and over 742,000 S3 requests—all at an infrastructure cost of around $10 per month. By prioritizing cost conscious design choices, the app’s architecture ensures that even significant growth—scaling to tens of thousands or even millions of users—would result in manageable increases in costs.

This article breaks down the design principles and decisions behind BestSelfApp’s architecture and explores how developers can rethink traditional patterns to build systems that are not only scalable but also remarkably affordable. Whether you’re managing a side project or an enterprise application, treating cost as a core design metric can unlock new opportunities and long term sustainability.

Affordability as a Strategic Advantage

Designing for affordability delivers more than just cost savings, it creates resilience and a competitive edge. When infrastructure costs are ultra low, systems become sustainable indefinitely without financial pressure, even during periods of slow growth or experimentation. Affordable architecture ensures that systems remain viable and adaptable, enabling strategies like competitive pricing and scalable user acquisition.

While the comparison might not seem flattering, I think of these as “cockroach apps”—resilient, adaptable, and capable of surviving under almost any conditions, including financial strain or minimal user engagement. Of course, I want the apps I build to thrive, but I also want to know they can survive long enough to uncover their potential. By designing with extreme cost sensitivity, these apps are given the runway they need to iterate, evolve, and discover what’s possible. In contrast, traditional systems with higher infrastructure costs are often forced offline when growth doesn’t meet expectations or when expenses outpace revenue.

This resilience naturally translates into a strategic business advantage. For BestSelfApp, operating on a budget this lean has made it feasible to support free users indefinitely, creating opportunities to grow organically and iterate on feedback without financial strain. Affordable systems aren’t just cost effective—they’re built to last. By prioritizing affordability, you create systems that can keep running for the long haul, freeing you to focus on growth and innovation without the constant worry of financial strain.

Affordability as a Core Design Principle

Affordability as a core design principle means making cost a primary consideration during the design and development phase, alongside performance, scalability, and functionality. It’s about making deliberate architectural choices from the start to ensure systems are as affordable as they are resilient. This requires challenging long standing default patterns and thinking critically about what your app truly needs.

Take storage, for example. For years, the default answer to “where do we store data?” has been “a database.” And even with the rise of serverless databases like DynamoDB, offering pay-per-use pricing, ease of setup, and high performance—this option, while convenient and within the serverless ecosystem, still can be costly with scale. Because databases have been the default for so long, many developers automatically reach for them without fully evaluating whether they’re necessary.

But here’s the thing: you don’t always need a database. Depending on your use case, S3 can often function just fine, especially for key value pair storage where ultra low latency response times aren’t critical. Even if you need some querying ability, the feasibility often depends on your workload. For backend or asynchronous processes, slower list operations can be acceptable, and alternative design strategies—such as redundantly storing data to enable efficient lookups from multiple keys—can make S3 a more viable option.

And those cost savings can’t be overstated. S3 is not only far cheaper than traditional databases but is also significantly less expensive than other serverless options like Aurora Serverless and DynamoDB—roughly 4X and 10X cheaper, respectively, for storage. This makes S3 an ideal solution for storing data that accumulates over time, such as user generated content or data tied to potentially inactive or abandoned users. Beyond cost, S3 offers unmatched durability and essentially infinite scalability, characteristics that set it apart even within the serverless ecosystem.

Cloud economist Corey Quinn has humorously and repeatedly referred to Amazon Route 53 as a database—an unconventional yet thought provoking perspective. He points out that Route 53’s DNS entries can essentially function as a lightweight key value store, illustrating how tools can sometimes be used in ways far beyond their traditional purpose. While I’m not suggesting we all rush to redesign our systems using DNS as a database, it’s a reminder that sometimes the most unorthodox solutions can provide the biggest cost savings. By thinking beyond traditional uses and default patterns, we open up opportunities to do more with less—aligning functionality, scalability, and affordability in unexpected ways.

Affordability as a core design principle isn’t about defaulting to the cheapest option in every case—it’s about prioritizing cost as a foundational value and making deliberate choices based on your app’s actual needs. This level of efficiency doesn’t happen by accident; it requires a mindset that challenges default patterns and critically evaluates architecture to align with both performance and financial goals.

Case Study: BestSelfApp’s Cost First Architecture

When I designed BestSelfApp, cost was a critical factor. With no immediate plans to monetize the app, it was important to ensure infrastructure costs remained so low that there would never be financial pressure to shut it down. This approach allowed the app to grow and evolve organically while collecting user feedback and exploring the best ways to iterate on it over time.

In its first three months, BestSelfApp served 858 users and processed hundreds of thousands of API Gateway requests, Lambda invocations, and S3 operations—all for what amounted to $0.04 per user. The table below provides a detailed breakdown of the AWS costs in the first three months.

Total AWS Costs for BestSelfApp 10/1/24 – 12/31/24

Key Highlights

Combined Costs for Dev and Prod Accounts: The costs above represent the total expenses for both my development and production AWS accounts, aggregated through AWS Organizations.

CloudWatch as the Top Expense: It’s both surprising and amusing that CloudWatch alarms and logs turned out to be the largest single expense. Given my background in site reliability engineering (SRE) and my strong advocacy for observability, it feels fitting—if a bit ironic—that I’ve spent more on monitoring and logs than anything else. This cost is primarily driven by verbose logging set to debug level, something that could easily be scaled back if needed.

S3 as the Primary Data Store: The app takes an unconventional approach by storing nearly all of its data—user information, daily tracking logs, and analysis results—directly in S3. Outside of authentication tokens stored in DynamoDB for ultra low latency access, S3 is the sole data store.  This choice ensured that costs wouldn’t accumulate unnecessarily, particularly for users who might abandon the app.

The Seed Costs More Than the Crop: It’s ironic how costs flipped in this setup. Lambda functions powered nearly half a million invocations, staying within AWS’s generous free tier limits. Yet one of the top expenses wasn’t the compute itself, but the cost of storing the container images that those Lambdas relied on. Normally, container image storage is a negligible cost compared to running instances, but here, it overshadowed the compute, flipping the usual cost expectations and highlighting the quirks of serverless pricing.

Big Analysis, Tiny Price Tag: The app’s heaviest compute task—generating nightly analysis for active users—was also surprisingly affordable. All the analysis generated over three months cost just $1.36. This workload involved ECS Fargate containers, each running for a few minutes per user each night to process data asynchronously. The cost effectiveness here reflects the careful design of running analysis only for active users and leveraging S3 for all input and output data.

A Significant Portion of Costs Are Non-Variable: A significant portion of these expenses—such as Route 53 hosted zones (four zones across dev and prod), ECR storage charges, and CloudWatch alarms—are largely non-variable and won’t significantly increase with usage. These stable expenses, accounting for roughly a third of the total, ensure that much of the app’s budget remains predictable, even as usage grows.

Resiliency Through Cost First Architecture

At just $0.04 per user, the cost of running BestSelfApp is remarkably low. What stands out most is that the infrastructure components directly tied to usage—Lambda, Fargate, API Gateway, and S3—account for only a small fraction of the total cost. The BestSelfApp case study illustrates that designing with cost as a core principle isn’t just about saving money—it’s about creating systems that are resilient, scalable, and sustainable over the long term.

Yet, this approach is far from automatic. Even in a cloud native environment, achieving this level of financial efficiency requires deliberate design decisions and a shift in mindset. The tools and capabilities to build scalable and radically cost effective systems have been available for some time, they are often applied selectively as many developers use serverless technology only for auxiliary tasks rather than fully embracing its potential for primary workloads.

The question isn’t whether this approach is viable—it’s what possibilities it could unlock for those willing to embrace it. With the maturity of cloud platforms and the proven capabilities of serverless technology, the opportunity to rethink how we design and build systems is firmly within reach. At its core, this is a story of resourcefulness: finding ways to do more with less, challenging traditional norms, and fully exploiting the tools at hand to build systems that are not only cost effective but also resilient and adaptable to change. It’s worth taking a step back to ask: are we fully leveraging these possibilities, or are we still stuck in the patterns of the past?