The stack behind 1prairie.menu
A plain inventory of the technologies we build on — the Google Cloud services, the open-source frameworks, and the deliberate decisions about what we don't run ourselves.
We’re a very small team shipping a product that has to feel like it was built by a much larger one. The only way that arithmetic works is to be ruthless about what we build versus what we rent.
This is an inventory of what 1prairie.menu runs on. No architecture secrets — just the technologies, and why each one is there.
The shape of it
Four tiers, and a deliberate rule about each: the client is a web app today, with a native iOS app in progress; the application tier is stateless containers; the data and AI tier is entirely managed; and public menus are served from the edge rather than from our application.
What we use from Google Cloud
Cloud Run runs everything we deploy. Our services are stateless containers that scale to zero between requests, which for a business our size is the difference between a hosting bill and a rounding error. It also means we never patch a server.
Firestore is the operational database. Document-shaped data fits a menu almost too well — a restaurant, its sections, its items — and the client libraries handle real-time updates without us building a socket layer.
Cloud Storage holds uploads and the generated artifacts: the menu photo or PDF you hand us, and the files we produce from it.
Vertex AI, running Gemini models, does the reading. When you upload a photo of a printed menu, this is the component that turns it into structured items, prices, and sections for you to review.
Firebase Authentication handles sign-in, including the social providers. Authentication is a category where rolling your own is all risk and no differentiation.
Cloud CDN and global HTTPS load balancing serve published menus. A diner scanning a code at a table should get a page in well under a second, on hotel wifi, at the edge nearest them.
Secret Manager holds credentials. Nothing sensitive lives in a config file or an environment we can’t rotate.
Cloud Build is our CI/CD. Pushes and release tags build and deploy without anyone running a command from a laptop.
BigQuery is the analytical warehouse, separate from the operational database, which is also where the pipeline in our next post lands its output.
Cloud Monitoring watches it, and tells us before customers do.
What we use from open source
Next.js and React, in TypeScript, for the operator-facing web app — the part restaurant owners use to edit and publish. Server-side rendering matters here because it’s the same technology that makes the marketing pages fast and indexable.
FastAPI on Python 3.12 for the API. Python is our standard for everything server-side, and FastAPI’s type-driven request validation eliminates an entire genre of bug at the boundary.
Swift and SwiftUI for the iOS app we’re building. It isn’t in the App Store yet — the toolchain and scaffold are in place and we’re working toward parity with the web app. It’s deliberately native rather than a wrapper around the web app, because camera capture is the first thing an operator does and native is simply better at it.
Astro builds this site — the one you’re reading. Static output, no client-side JavaScript framework shipped to your browser for what is fundamentally a document.
Tailwind CSS for styling, shared as one configuration across the products so they look like siblings.
Terraform describes our infrastructure. Projects, buckets, service accounts, and network configuration are code that gets reviewed, not console clicks someone half-remembers.
pnpm and Turborepo run the monorepo. Vitest and pytest are the test suites. The Firebase Emulator Suite means local development touches no cloud resources and costs nothing.
What we deliberately don’t run
The inventory above is short, and that’s the point. We don’t operate a Kubernetes cluster, a message broker, a search cluster, a cache tier, or a CI fleet. Every one of those is a real technology with real merit, and every one is also a thing that pages somebody at 2am.
Managed services have a genuine cost — you inherit someone else’s constraints and their pricing decisions, and portability gets harder the deeper you go. We think that trade is correct at our size, and we’d rather revisit it when scale forces the question than pre-build for a scale we haven’t reached.
The test we apply to any new piece of infrastructure is simple: does running this ourselves make the product better for a restaurant owner? Usually the answer is no.
Next in this series: how we use Airflow and Astronomer to find restaurants worth talking to.