"Technically achievable" and "financially sustainable to keep running" are two different problems. For a solo-built product, infrastructure that costs nothing when traffic is low but scales gracefully when it grows is not a nice-to-have — it is the foundation everything else sits on.
This post covers the actual monthly cost of running Storyie in production, the reasoning behind each service choice, and the specific configuration decisions that keep the bill low.
TL;DR
Layer | Service | Monthly cost |
|---|---|---|
Compute + CDN | AWS (Lambda / CloudFront / S3) | ~$0.30 |
Database + Auth | Supabase (Pro) | $25 |
Image storage | Cloudflare R2 | $0 (10 GB free) |
Resend | $0 (100/day free) | |
Payments | Stripe | 3.6% of revenue, no fixed fee |
Push notifications | Firebase Cloud Messaging | $0 |
Total fixed cost | ~$25 |
Supabase Pro is the only real fixed cost. AWS runs at ~$0.30, which is almost entirely S3 storage for static assets. Everything else is either free-tier or pay-as-you-go with no baseline charge.
AWS: Lambda + CloudFront with no fixed fee
The SST v3 setup
Storyie's web app is a Next.js deployment on AWS via SST v3. The physical topology is straightforward:
CloudFront (CDN)
├── S3 (static assets)
└── Lambda (SSR / API Routes)Each layer has favorable billing characteristics at low traffic:
- Lambda: one million requests free per month, then fractions of a cent per request
- CloudFront: 1 TB of data transfer free (first 12 months), global CDN coverage included
- S3: a few GB of static assets adds up to cents
In practice, Lambda and CloudFront have stayed inside their free tiers since launch. The $0.30 monthly AWS bill is S3 storage.
ARM64 and right-sized Lambda memory
Two configuration choices directly affect Lambda cost.
ARM64 (Graviton2) architecture costs about 20% less than x86 for the same workload and typically performs the same or better. In SST terms it is a one-line change:
server: {
memory: "1024 MB",
runtime: "nodejs22.x",
architecture: "arm64",
timeout: "20 seconds",
},Right-sized memory for Cron jobs. Lambda allocates CPU proportional to memory. Running every job at the maximum tier wastes money; running everything at the minimum makes CPU-heavy jobs slow. Storyie has about 10 Cron jobs:
Job type | Memory | Schedule |
|---|---|---|
Email dispatch | 256 MB | Every 5–15 minutes |
Aggregation / tag management | 512 MB | Every 1–4 hours |
Monthly AI report | 1024 MB | Once per month |
Matching memory to actual workload roughly halves Lambda cost compared to blanket over-provisioning.
CloudFront caching
Fewer Lambda invocations means lower cost. Cache headers do the work:
assets: {
// Versioned JS/CSS: cache forever at the CDN
versionedFilesCacheHeader: "public,max-age=31536000,immutable",
// Non-versioned files: CDN TTL of one day, refresh in background
nonVersionedFilesCacheHeader: "public,max-age=0,s-maxage=86400,stale-while-revalidate=8640",
},Auth routes under /api/auth/* get the AWS-managed CachingDisabled policy applied explicitly. An OAuth callback cached by a CDN would silently break every login — this is the kind of bug that is obvious in retrospect and invisible until it hits a real user.
Supabase: Pro plan at $25/month
Why we started on Pro
The free tier is fine for a prototype. For a Lambda-based production deployment, it has two problems.
First, Lambda creates a new Postgres connection on every cold start. Concurrent requests stack up quickly, and the Free tier connection limit is low enough that moderate traffic produces connection errors. Starting with Pro eliminated that class of issue from day one.
Second, Free gives 500 MB of database storage. That sounds like a lot until you account for index overhead as your schema grows through migrations. Pro gives 8 GB, which is headroom we are not going to exhaust.
The third reason is data durability. Storyie stores user diaries. Losing that data is not an acceptable failure mode. Pro includes Point-in-Time Recovery; Free does not.
Free | Pro ($25/month) | |
|---|---|---|
Database storage | 500 MB | 8 GB |
Backup | Daily snapshot | Point-in-Time Recovery |
Bandwidth | 5 GB | 250 GB |
File storage | 1 GB | 100 GB |
What we actually use
We give Supabase one job: database and auth. Supabase Storage and Edge Functions are not used — those workloads go to R2 and Lambda respectively. Keeping Supabase's role narrow means we are not paying for capacity we do not need, and it keeps the dependency graph simpler.
Cloudflare R2: image storage with free egress
S3 vs R2
Egress is where image storage costs live. S3 charges $0.09 per GB transferred out; R2 charges nothing for egress. At any meaningful image delivery volume, R2 wins by a large margin.
S3 | R2 | |
|---|---|---|
Storage | $0.023/GB | $0.015/GB |
Egress | $0.09/GB | $0 |
PUT/POST | $0.005/1000 | $0.0045/1000 |
R2 also includes 10 GB of free storage per month, which covers us entirely for now.
Presigned URL upload pattern
Images never pass through Lambda. The flow:
Client → API Route (get presigned URL) → Client uploads directly to R2This keeps Lambda execution time low (the API route just generates a URL and returns), avoids unnecessary data moving through the server, and lets R2 handle the heavy I/O. Cost and latency both improve.
Email, notifications, and payments
Resend
Resend's free tier covers 100 emails per day. Storyie sends welcome emails, weekly summaries, milestone notifications (first diary, 7-day streak, etc.), and monthly AI reports for Pro subscribers. At current user counts we have not hit the free tier ceiling. The paid plan is $20/month for 50,000 emails — we will cross that threshold when daily active users reach the hundreds.
Firebase Cloud Messaging
FCM is free with no practical usage limits. Push notification delivery costs nothing. The Lambda-side Cron job that checks for pending reminders every 15 minutes runs at 256 MB and fits comfortably inside the Lambda free tier.
Stripe
No fixed fee. We pay 3.6% of processed revenue (Japan rate). If revenue is zero, cost is zero. This is the right model for a product still finding its footing.
Three principles behind the cost structure
Prefer pay-as-you-go over fixed fees
Fixed-fee services charge whether you have users or not. Lambda, R2, Resend, and Stripe all have zero baseline cost. The only exception is Supabase Pro, and that is a deliberate trade-off for connection headroom and data durability — both of which have hard failure modes on the free tier.
Stack free tiers across services
No single service's free tier covers an entire app. Combined, they cover most of it:
- Compute: Lambda (1M requests/month)
- CDN: CloudFront (1 TB/month)
- Images: R2 (10 GB + no egress)
- Email: Resend (100/day)
- Notifications: FCM (unlimited)
- Payments: Stripe (percentage only)
The one gap is database, and that is where the $25 goes.
Do not optimize for hypothetical scale
"What if we get 100,000 users?" is a future problem. Lambda, Supabase, and R2 all have upgrade paths. Right now, the goal is to run a real production service at a cost that does not require revenue to justify. $25/month clears that bar by a comfortable margin.
Summary
The decision log, in short form:
Decision | Outcome |
|---|---|
Lambda over EC2/ECS | No fixed compute cost |
R2 over S3 | Free egress for image delivery |
ARM64 architecture | ~20% Lambda cost reduction |
Right-sized Cron memory | Avoids over-provisioning on background jobs |
Supabase Pro from day one | No connection limit issues; PITR included |
Supabase Storage not used | Keeps Supabase narrowly scoped to DB + Auth |
Choosing infrastructure because it is cheap enough to sustain during the phase when you have no users — not because it is technically interesting — is what keeps a product running long enough to find the users. That perspective shapes every decision above.
Related Posts
- Building a Monorepo with pnpm and TypeScript — the workspace setup that ties the web and mobile apps together
- Next.js 16 on AWS with SST v3 — how we wire up the Lambda + CloudFront deployment in detail
- Cross-platform Lexical with
use dom: monorepo gains and the bridges you still own — how we share the rich-text editor across web and mobile
Try Storyie
If you want to see what this infrastructure serves, try writing a diary at storyie.com. The iOS app opens the same content — the $25/month stack handles both sides.