Serverless
A to-do app that runs on nobody's server
Building a fully serverless, event-driven reminder app on the AWS free tier, Lambda, DynamoDB, Cognito, and EventBridge + SNS for scheduled emails. No servers to patch, no cron to babysit, no monthly bill.
I wanted a to-do app with scheduled email reminders. I did not want a server I’d have to patch, a cron daemon I’d have to remember, or a bill at the end of the month. So I built the whole thing to run on nobody’s server, fully serverless, entirely on the AWS and Cloudflare free tiers.
The shape of it
- Frontend on Cloudflare Pages, static, fast, free.
- Backend in Node.js + TypeScript on AWS Lambda, code that only exists while it’s running.
- DynamoDB for storage, pay-per-request, scales to zero, no instance to size.
- Cognito for auth, I didn’t want to own a password table.
The interesting part: reminders without a scheduler
The obvious way to send “remind me at 9am” emails is a cron job. But cron means a process that’s always alive, which means a server, which is exactly what I was trying to avoid.
Instead the reminders are event-driven:
- EventBridge carries the scheduling, a rule fires when a reminder is due.
- SNS fans that event out to email.
There’s no loop polling the database asking “is anything due yet?” The event itself is the trigger. Nothing runs until something needs to happen, and then exactly the right thing happens.
Why bother
Two reasons, and they’re the same reason.
It costs nothing at rest. Scale-to-zero isn’t a buzzword here, when no one’s using the app, there is literally nothing running and nothing to pay for. The free tier covers the rest.
There’s nothing to babysit. No OS updates, no disk filling up, no cron job that silently died three weeks ago. The infrastructure is the cloud provider’s problem, and I get to think about the app instead.
The trade-off is real: serverless makes you architect around events and cold starts, and local development takes more setup than node server.js. But for a thing that should just keep working without me, it’s the right shape, the app does nothing until it has a reason to, and then it does exactly that.