Every Developer Has a First Project. Mine Followed Me for a Decade.
I'm writing this on March 24th, 2026. This may or may not be a cool project depending on when you read this — but right now, I'm pretty excited about it.

Where It All Started
I started my career as a software developer building e-commerce websites for restaurants. Nothing fancy — basic static sites at first. HTML, CSS, maybe some jQuery if I was feeling adventurous. Then I built a simple online ordering system on top of one of those sites. At the time, it felt like the coolest thing I'd ever made. Customers could actually browse a menu and place orders online. Revolutionary, right?
That project taught me the fundamentals — REST APIs, database design, payment integrations, the whole stack. It was scrappy and far from perfect, but it worked, and it gave me a foundation I've built on ever since.
Fast Forward to Today
Years later, I found myself curious about a question: how much can a single developer actually build in 2026? With AI augmenting the development process, what's the upper bound on what one person can ship on weekends?
I needed a project to test that. And when I looked at the restaurant e-commerce space — a domain I know well — I noticed some recurring gaps:
- Multi-locale support is rare. Many platforms don't handle translations at all. If you're running a restaurant in a multilingual country, you're piecing things together yourself.
- Product modifiers are an afterthought. Pizza toppings. Spice levels. Extra cheese. Portion sizes. These aren't edge cases for restaurants — they're the core of how menus work. Yet many platforms don't model them properly.
- Pricing is all over the place. Some solutions are genuinely good, but unreasonably expensive for a small restaurant just trying to get online orders going.
There are good solutions out there — I'm not saying there aren't. But I thought: this is the perfect domain to stress-test what a single dev with AI leverage can actually ship. Something I know deeply, with enough complexity to be a real challenge, and useful enough that people might actually use it.
The Idea
The core idea: anyone should be able to install a package into a Next.js project and have e-commerce functionality that works out of the box with some simple configuration. Not a separate platform you integrate with, but something that lives inside your project as a first-class citizen.
I'd seen how PayloadCMS does this — you install it, configure it, and it just works inside your existing app. Developers loved that pattern. I thought: what if e-commerce worked the same way?
Vercel, Cloudflare, self-hosted — it shouldn't matter where you deploy. That constraint shaped every technical decision that followed.
That's where ShopHost was born.
Technical Decisions (And Why)
I want to go deeper here than just listing a tech stack, because the interesting part isn't what I used — it's why.
Three Packages, One Install
ShopHost is a monorepo (Nx + pnpm) split into three packages:
@shophost/rest-api— The backend, powered by Hono.@shophost/react— Admin dashboard + storefront UI components.@shophost/client— A TypeScript SDK for API calls.
Why Hono over Express? Runtime agnosticism. Hono runs on Node, Bun, Deno, Cloudflare Workers, Vercel Edge — it doesn't lock you into one deployment target. That directly supports the "works on any infra" constraint. It's also lightweight with excellent TypeScript support and middleware bindings via c.get("auth"), which keeps the handler code clean.
Why a generated client? I went with an OpenAPI-first approach. Every API route uses Zod schemas that serve double duty — they validate input at runtime and generate an OpenAPI spec. That spec then auto-generates the TypeScript SDK via @hey-api/openapi-ts. One source of truth: change a schema → client updates automatically → no manual SDK maintenance. It's the kind of decision that saves hours over the life of a project.
The "Install and Go" Pattern
This is the core innovation. A consuming app does:
pnpm add @shophost/react @shophost/rest-api @shophost/clientThen mounts a route handler and passes config (database URL, Stripe keys, auth settings). No forking repos, no boilerplate. The package owns the Prisma schema and database logic — the host app just provides environment variables.
const handler = createNextHandler({
database: { connectionString: process.env.DATABASE_URL },
auth: { baseURL: process.env.NEXT_PUBLIC_API_BASE_URL },
payment: { stripe: { secretKey: "...", paymentMethods: ["card", "blik"] } },
});Product Snapshots for Order Immutability
This one's subtle but important. When a customer places an order, the order item doesn't point to the live product — it points to a snapshot of the product at purchase time. If a restaurant updates their menu or deletes a product later, every past order still has the exact product data from when the customer bought it. Price, name, modifiers — all frozen in time.
It's the kind of thing you don't think about until you've worked in e-commerce and seen what happens when you don't have it.
Multi-Locale by Design, Not Bolted On
Every translatable entity — products, categories, modifier groups — has a dedicated translation table per locale. The API accepts a ?locale= query param and returns flattened, localized responses. The system supports 143 locales out of the box.
Most platforms treat i18n as an afterthought. I made it a first-class schema concern because I've seen how painful it is to retrofit translations onto an existing data model.
Cart Revalidation
The frontend cart lives in localStorage, but it's never trusted for display. Every render, the cart revalidates against the backend — checking that products still exist, prices haven't changed, and modifiers are still valid. Stale items get flagged. Totals are recalculated server-side.
It's a small detail, but it prevents the class of bugs where a customer sees one price and gets charged another.
How AI Helped (And Didn't)
I used AI heavily throughout the process. But I wouldn't call it "vibe coding" — that would imply I never read the code and just let the AI do its thing.
It's more like managing a team of juniors.
You decide the high-level architecture. You set the coding patterns — every feature follows the same four-file structure: schema.ts, route.ts, handler.ts, service.ts. You determine what actually needs to be built and in what order. Then you use AI tools to get the implementation done faster. You review everything. You catch the mistakes. You refactor when the AI takes a wrong turn.
The architecture decisions — why OpenAPI-first, why product snapshots, why cart revalidation — that's all human judgment. The AI didn't decide those things. But once I decided them, AI helped me implement 26 feature modules, a full admin dashboard, storefront components, integration tests with Docker PostgreSQL, and a generated TypeScript SDK. As a single developer. On weekends.
That's the leverage I was testing. And it's real.
It's Not Perfect
I want to be upfront — this project is nowhere near perfect. There are shortcuts. There's tech debt I'm aware of and probably some I'm not. Some things were built quick-and-dirty to get a working version out the door rather than polished to production standards.
But that's kind of the point. The goal was never to ship a flawless product on weekends — it was to ship a useful one. Get the architecture right, make the core patterns solid, and iterate. Perfection is the enemy of actually putting something out there.
Already in the Wild
A couple of stores are already using ShopHost despite the rough edges. Real businesses, real orders, real customers. The feedback has been quite good.
That's the most satisfying part. It started as an experiment to test the limits of single-developer leverage, and it turned into something people actually rely on to run their businesses.
What's Next
There's an extensive roadmap — inventory management, CMS integration, shipping provider integrations (DPD, Wolt, Stuart), discount codes, API key auth, rate limiting, webhooks, and more. The kind of features that turn a good tool into a great one.
But the foundation is solid. The architecture is clean. And the pattern — install a package, configure, ship — feels right.
Full Circle
There's something poetic about it. I started my career building scrappy ordering systems for local restaurants. Now, years later, I'm building an open source platform that solves the same fundamental problem — but with proper architecture, proper tooling, and the kind of leverage that didn't exist when I started.
If you're curious — ShopHost is on GitHub. MIT licensed, contributions welcome. Check the code, open an issue, or just poke around. I'd love to hear what you think.