Slyderz is a marketplace that connects food-truck owners with the people who

want to find them. A customer-facing web app, a management dashboard for truck

operators, an iOS app, and a content site, all sharing one backend.

This post is about the architecture that lets all of that live in a single TypeScript

monorepo and deploy to zero traditional servers.

The short version: everything runs on Convex for the application layer and

Cloudflare Workers for the web layer, glued together by a pnpm + Turborepo

monorepo and a branch-driven GitHub Actions pipeline. When code lands on

staging or main, it's live a few minutes later.


One monorepo, five apps, four packages

The whole product is one repository with pnpm workspaces and Turborepo at the

top level. A shared catalog in pnpm-workspace.yaml pins the versions of the

big dependencies (React, Next.js, TypeScript, Tailwind) so every app upgrades in

lockstep instead of drifting.

What lives under apps/ and packages/:

- consumer — the customer-facing site. Next.js 16 with the App Router,

Tailwind v4, React Query, and Stripe for payments.

- dashboard — the operations hub for truck owners: menu, orders, calendar,

hours and locations, reviews, customer CRM, and Instagram integration. It's

TanStack Start (Vite + TanStack Router) with typed server functions, deployed

to Cloudflare Workers.

- mobile — an Expo SDK 57 app with expo-router, native maps, Location,

and Stripe in-app payments. Same auth, same Convex API as the web apps.

- blog — Astro + EmDash, an

edge-native CMS that runs on Cloudflare Workers with D1, R2, and KV.

- packages/backend — the Convex backend, consumed by every app.

- packages/ui — the shared component library (shadcn-style, built on

base-ui) with a branded theme, bundled with tsdown into per-component

entry points.

- packages/email — transactional email templates (jsx-email) rendered

server-side by the backend for auth flows, invoices, and waitlist signups.

- packages/validators — shared Zod schemas so validation never drifts

between client and server.

The key idea is that the backend is also a workspace package. Apps import the

generated Convex API (@workspace/backend/convex/_generated/api) directly, so

there's no REST layer to maintain and no hand-written client to keep in sync —

the types are generated and shared.

Convex is the system of record

All product data organizations, menus, orders, locations, hours, reviews,

payment providers, and social posts lives in one Convex app. Convex gives us

reactive queries, mutations-as-transactions, schedulers, and HTTP actions out of

the box, plus a component ecosystem that replaces most of what I'd otherwise

hand-roll:

- better-auth for auth (email/password + OAuth) stored as a Convex component.

- Stripe for payments and connected accounts for truck operators.

- Resend for transactional email (with a kitchen sink of edge cases handled

by a cron that purges stale emails once an hour).

- R2 for media uploads, served through a CDN

- Workflow for the multi-step Instagram messaging flows with durable

execution and retries.

- PostHog for product analytics.

Because everything is one Convex app, a query from the dashboard and one from

the mobile app hit the same code. Cross-cutting concerns like "this truck is no

longer accepting orders after closing time" are enforced in one place, not

reimplemented per client.

The blog runs at the edge

The blog was the fun one. Instead of attaching a database to a traditional CMS,

it's an Astro site rendered by @astrojs/cloudflare, with EmDash providing the

admin UI and content model. Content lives in D1 (Cloudflare's SQLite), media

in R2, and rendered pages are cached in KV. Scheduled workers rebuild

stale content in the background, and caching rules revalidate aggressively (SWR

on the homepage). Full-text search, RSS, and JSON-LD all come free. It's the

rare CMS where the compute and storage sit in the same edge network as its

readers.

Deployment: branch = environment

CI is a single GitHub Actions workflow (deploy-dashboard.yml) that treats the

git branch as the environment:

- Pushing to staging builds and deploys the dashboard to a

dashboard-staging Worker

- Pushing to main deploys to dashboard-production behind

dashboard.slyderz.co.

- Both jobs also run convex deploy using an environment-scoped deploy key, so

the Convex app reflects the same branch that produced the worker.

The workflow is split into build and deploy jobs: the build job compiles the app

with environment-specific build-time variables (scoped in GitHub environment

secrets) and uploads dist/ as an artifact; the deploy job downloads that

artifact and hands it to cloudflare/wrangler-action. That keeps the build

hermetic and the deploy job a pure "publish this exact output" step.

Environment configuration lives in wrangler.jsonc as an env block per

environment. The staging and production Workers share one config with their own

names, vars (Convex URLs, PostHog keys, site URLs) and custom-domain routes.

OpenTelemetry-style observability is toggled on for production through the same

file.

The Takeaway

None of this requires managing infrastructure. Convex owns the data and the

business logic; Cloudflare owns the edge compute, storage, and CDN; GitHub

Actions turns a merge into a deploy. The platform choice was the architecture

decision. It meant one small team could build a marketplace spanning web,

mobile, payments, email, and content publishing without ever provisioning a

server.

The project is live at:

Consumer - slyderz.co

Dashboard - dashboard.slyderz.co

Blog - news.slyderz.co.