Skip to content
All work
Live

2026

Canny Cart

A shopping list you talk to. It sorts what you said into aisles, reads your receipts, and works out where the money went.

v1.0.5 · Free · iOS 16.4+ · Shopping

The app

Canny Cart — App Store screenshot 1 of 4
Canny Cart — App Store screenshot 2 of 4
Canny Cart — App Store screenshot 3 of 4
Canny Cart — App Store screenshot 4 of 4

Problem

Household shopping lists live in group chats and get lost. The hard part isn't the list — it's keeping web and mobile genuinely in sync without maintaining two backends.

My role

Sole engineer and designer: schema, backend, both clients, design system.

Outcome

An npm-workspaces monorepo where a Next.js web app and an Expo mobile app share a single Amplify Gen 2 backend, a single auth model and a single set of design tokens.

Canny Cart is a monorepo with three moving parts: an Amplify Gen 2 backend (Cognito, AppSync, DynamoDB), a Next.js web app, and an Expo mobile app. All three share one schema and one design token file, which is the whole point — a change to the data model lands in both clients at once.

The interesting constraints were mobile-side. DynamoDB has no GROUP BY, so ranking a user's most-added items had to become a client-side aggregation. Reusable list templates turned out to need one boolean on an existing model rather than a new table. Offline behaviour meant mutations had to survive an app kill and replay on reconnect.


Build log

39 posts · Jul – Sept 2026

Written while building, not after. Each one is a decision and the trap that made the obvious approach fail.


Stack

Next.js
Expo
TypeScript
AWS Amplify Gen 2
AppSync
DynamoDB
Cognito
MUI
NativeWind