I built a serverless checklist app with no servers and no CI/CD pipeline — just Lambda, API Gateway, S3 and DynamoDB, all created from CloudShell with the AWS CLI. This is the story of that build: what it does, how the pieces connect, the one permission bug that hid my data, and what it costs.
What I Built
A small checklist app: create items, list them, and mark them complete. The frontend is a static page on S3, and every action goes through a single HTTP API:
- Website: http://serverless-checklist-tracker-012517218229.s3-website-us-east-1.amazonaws.com/
- API: https://lm1jbisu36.execute-api.us-east-1.amazonaws.com/items
Try it from a terminal:
curl -X POST https://lm1jbisu36.execute-api.us-east-1.amazonaws.com/items -H 'Content-Type: application/json' -d '{"title": "Ship the Weekend Challenge project"}'
curl https://lm1jbisu36.execute-api.us-east-1.amazonaws.com/items
How the pieces connect
- S3 hosts the static website (HTML, CSS, JavaScript).
- API Gateway exposes a REST API with routes like POST /items, GET /items, PUT /items/{itemId}/complete and DELETE /items/{itemId}.
- Lambda (Python 3.12, function
serverless-checklist-api) implements all four operations. - DynamoDB table
serverless-checklist-itemsin PAY_PER_REQUEST mode stores the data, using an auto-generated item ID as the key. - IAM uses a least-privilege role so the function can only read and write that one table.
Everything lives in us-east-1, under AWS account 012517218229. There is no EC2 instance, no container, and no deployment pipeline — the code was deployed straight from CloudShell with AWS CLI commands.
The bug that hid my data
After the first deploy, POST /items returned an ID and a 201 — but GET /items/{itemId} returned "Item not found". The item never reached the database. The cause was the IAM role: the function was deployed with an incorrect role, so it had no DynamoDB permissions and failed silently. The fix was a dedicated least-privilege role with the actions the function needs on that one table. The test runs after the fix all returned HTTP 200.
Why this output matters
This is a build: real infrastructure, real code, real costs. I built it for the AWS Builder Center Weekend Challenge "No Pipeline, No Problem" (Nov 13–16, 2026), where the rule is simple — serverless AWS services only, no servers and no pipelines.
What it costs
Lock-in is close to free. DynamoDB PAY_PER_REQUEST has no base charge for the test volumes I used, Lambda and API Gateway bills for this build were USD 0.00, and the S3 static site costs almost nothing.
What I learned
- Read error messages literally: a 404 can be a permissions problem, not a missing record.
- Keep IAM roles per-function, scoped to exactly one table and only the actions the function uses — it converts a silent failure into a clear permission error.
- Serverless only works if the deploy path is just as simple: build the way you run, with the same CLI commands every time.
What next?
I am adding a short demo video (under 3 minutes) showing the website and the API in action, and more security hardening for the API — throttling, authorizers, and input validation. If you build serverless checklists of your own, what guardrail do you add first?
Top comments (0)