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 self-hosted PocketBase as the backend.
- 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 five packages.
apps/
├─ mobile/ ── Expo + React Native + Unistyles ─┐
└─ web/ ── Vite + React 19 + Tailwind ──────┤
│
packages/ │
├─ shared/ ── types · hooks · logic ◀───┤
├─ auth/ ── PocketBase client ◀───┤
├─ icons/ ── codegen'd SVGs ◀───┤
├─ category-icon/ ── picker UI ◀───┤
└─ i18n/ ── translations ◀───┘
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 (Unistyles on mobile, Tailwind on web) stays in the app it belongs to.
The mobile app recently moved off Tamagui to Unistyles — styling that resolves in C++ over JSI, so a theme switch never bounces through the React tree — paired with a native tab bar and a shared “Warm Sage” palette the web app mirrors in Tailwind. Same design language, two rendering stacks. Dropping Tamagui also took a chunk out of the bundle and stopped the build from breaking every time Expo ships a major.
$ bun run stats
- platforms shipped from one repo 3 (ios / android / web)
- shared business-logic loc 6 000
- generated icon components 501

The backend: PocketBase
Started on Firebase, moved off it. 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 now runs on PocketBase: a single Go binary that hands me auth, a database, and file storage behind a plain REST API, with the data sitting on a PocketBase instance I control — hosted on elest.io — instead of someone else’s dashboard.
Its client is just a typed wrapper over HTTP, so it behaves identically on mobile and web — nothing native to go feral when Expo bumps a major. Sessions persist through an AsyncAuthStore (Expo SecureStore on mobile, browser storage on web) with token refresh on a timer; password and OAuth2 sign-in both work. 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.
Where it’s going
This one has an actual written roadmap — each feature lives as a self-contained spec in the repo, with data model, architecture, and build phases sketched before any code. Recent releases shipped manual nutrition tracking, a baking knowledge base (Poradnik — glossary terms linked inline in recipe steps), and a home dashboard. Next up is the one with the biggest daily payoff: plan a week of meals, get one deduplicated shopping list compiled across everything.
$ bun run roadmap
- [x] manual nutrition + macro card v0.2.0
- [x] poradnik — glossary + inline step terms v0.3.0
- [x] home dashboard shipped
- [>] meal planner → auto-compiled shopping list next
- [ ] public recipes + discovery feed
- [ ] pantry + "what can I cook?"
- [ ] collections / cookbooks
- [ ] household sharing
- [ ] cooking mode — timers · voice · offline