Przepisnik
A recipe book for home bakers — same code, three places
Cross-platform recipe and cake-planning app. Turborepo + Bun monorepo sharing business logic between an Expo mobile app and a Vite web app, with Firebase as the backend (REST, no SDK).
- statusside project
- modelside project
- since2024
- > solo, evenings and weekends
Przepisnik (“recipe book” in Polish) is a recipe-management app for home bakers. Save recipes, plan multi-tier cakes, scale ingredients, walk through bakes step by step. iOS, Android, and web — all driven by the same TypeScript code.
The monorepo
Turborepo + Bun workspaces, two apps and four packages.
apps/
├─ mobile/ ── Expo + React Native + Tamagui ─┐
└─ web/ ── Vite + React 19 + Tailwind ────┤
│
packages/ │
├─ shared/ ── types · hooks · logic ◀───┤
├─ auth/ ── Firebase REST client ◀───┤
├─ icons/ ── codegen'd SVGs ◀───┤
└─ category-icon/ ── picker UI ◀───┘
The split is deliberate. Anything that doesn’t render — recipes, ingredients, cake planner, ingredient parser, shopping list, query orchestration — lives in packages/shared and gets imported by both apps. Anything platform-specific (Tamagui on mobile, Tailwind on web) stays in the app it belongs to.
$ bun run stats
- platforms shipped from one repo 3 (ios / android / web)
- shared business-logic loc 6 000
- generated icon components 501
Firebase, but REST
Native Firebase SDKs and Expo don’t always get along — every upgrade is an opportunity for the build to break in a creative new way. The whole thing talks to Firebase via the REST API (Identity Toolkit + Realtime Database + SecureToken). Slightly more code to write, far less misery to maintain.
Tokens go into Expo SecureStore on mobile, browser storage on web; the auth context lives in packages/auth and is identical on both platforms.
The baker-specific bits
- Recipes have nested steps with per-step ingredients, so “preheat the oven” and “add 200g of butter” are first-class objects, not lines in a paragraph
useIngredientParserturns “200g flour” or “1 1/2 tsp baking soda” into structured{ amount, unit, name }so scaling actually worksuseCakePlannerCorehandles tier sizing, portion math, and ingredient roll-up across multi-recipe bakes
Offline + persistence
TanStack Query + persistQueryClient keep recipes available when you’re in a kitchen with bad signal — which, if you’ve ever tried to bake from a phone, is most of the time.