One backend.
Every app trusts it.
The website, the desktop app, the admin panel, the mobile app, and the extension all talk to one API. A change on the server shows up as an error in the editor, not as a bug report from a customer.
GET/organizations2006ms
POST/invitations20012ms
GET/settings/members2008ms
PUT/members/role2009ms
GET/auth/session2004ms
- Website
- Desktop
- Admin
- Mobile
- Extension
one api, every app, one set of types
Rename a column. Every layer notices.
One name, declared once in the database and inherited by every layer above it, all the way to the button a customer clicks. Catching this while typing is cheaper than catching it in production.
organization.seat_limit
Postgres
the column
seat_limit integerPrisma
the schema
seat_limit IntKysely
the query
.select("seatLimit")Hono
the API route
c.json({ seatLimit })React
the UI
{data.seatLimit}
The compiler finds every screen that breaks
Change a field and every affected query, route and component shows up as a list. Nothing waits to be discovered in production.
Refactors stop being scary
Rename, restructure, then follow the errors to done. When the list is empty, the change is complete everywhere.
AI agents fix their own mistakes
A wrong guess fails the typecheck in seconds. The agent reads the error and corrects itself instead of shipping broken code.
Five apps that cannot drift apart
Frontend, admin, mobile, and extension all read the backend's types, so an API change never leaves one of them quietly behind.
Nobody wrote a test for any of this. It is what the compiler already does when every layer shares one set of types.
What a backend costs in month six.
Not on day one. On day one every backend is fine. These are the three bills that arrive once the product has customers and the team has moved on to the next feature.
The frontend finds out after the customer does
one incidentA hand-written API client nobody trusts
a week a quarterErrors swallowed where nobody looks
silent churn
The compiler reports it before anyone ships
zero incidentsThe client writes itself from the routes
zero upkeepEvery error ends up in one place you watch
no surprises
5
your api
web
admin
mobile
Apps served by one backend
Website, desktop, admin, mobile, and extension, all reading the same typed API. One more app is one more client.
0
routes in, sdk out
nothing to keep in sync
Hand-written API clients to maintain
Every route becomes a typed call on the frontend the moment it exists. No client to write, no client to let rot.
1
loggedalwaysreportedsentryansweredtypedPlace every error is handled
Logged, shaped into a response, and reported to Sentry by one middleware. Nothing dies quietly.
What it does for the business, and where to check.
Nine things the backend gives you, in plain language. The line at the bottom of every card is where your developer goes to confirm it. The whole repo is public, so nothing here asks for trust.
One backend serves every app you have
Website, desktop, admin panel, mobile app, and browser extension all read the same API. Adding a new app is a client, not a second backend and a second team.
Consumed by5 apps, one SDKA breaking change cannot sneak out
When the API changes, every screen that depends on it stops compiling until someone fixes it. The list of what broke is produced by the compiler, not by your customers.
Caught bypnpm typecheckIt is tested before it ships, every time
Unit tests, integration tests, and an end-to-end project for the API run on every commit. Green means green, and a red build never reaches production.
Runs inapps/backend-e2e · CIWhen something breaks, you hear about it first
Every error passes through one place that logs it, shapes the response, and reports it to Sentry. Nothing fails quietly inside a forgotten catch block.
Reported toSentry, one middlewareLive updates without a rewrite
Real-time events are wired with the same type safety as ordinary requests. A live dashboard or a notification bell is a feature, not a migration.
Typed byhono-ws-converter.tsWho can do what is never a guess
Permissions are checked against a fixed list of actions, so a typo in an access rule stops the build instead of exposing a customer's data.
Enforced byCASL, typed subjectsA bad day is a slow day, not a down day
Responses are cached, and when the cache goes away the API keeps answering from the database. Customers see a slower page, not an outage.
Cached inValkey, fails softIt refuses to start half-configured
Every setting is checked at boot. A missing key fails on the developer's machine with a clear message instead of failing for customers at 2am.
Validated byZod env schemaYour data stays in a database you own
Standard Postgres on a host you choose, with migrations tracked in the repo. Any backup tool, any analyst, any future team can work with it.
Stored inPostgres 17 · Prisma migrations
Deploy with one command.
One command ships everything: web apps and services on your own hosting, the mobile app through EAS, the extension to the stores. No dashboards, no YAML.
- Creates every service on your host
- Wires the URLs, secrets, and CORS between them
- Runs your migrations once the API is up
- Then offers the mobile app (EAS) and the extension stores
launch sequence
one command
- Applicationlive
- Admin Panellive
- APIlive
- Mobilelive
- Extensionlive
- Serviceslive
What the backend does not include.
Better you read it here than find out on day two.
Auth, billing, notifications, collaboration
Feature packs. Each one adds its routes, schema, and tests to this backend with one command.
Your business logic
The plumbing is done. The thing that makes your product yours is still yours to write.
Show this part to your developer.
Ordinary, popular tools, current versions, pinned. Anything here, a backend developer you hire has already used.
- 5
- apps on one API
- 0
- hand-written API clients
- 1
- place every error is handled
- 3
- e2e projects, one per app
- Framework
- Hono 4 on Node, Zod 4 validating every request at the edge.
- Database
- Postgres 17 on the pgvector image. Prisma 7 for schema and migrations, Kysely for typed SQL.
- Cache
- Valkey (Redis-compatible), wired in and allowed to fail soft.
- Types
- Routes exported as a typed SDK through HyperFetch. Sockets typed the same way.
- Safety
- CASL permissions, one error middleware, Sentry for node, env checked at boot.
- Testing
- Vitest 4 unit and integration suites, a backend e2e project, Nx-cached CI.
What the backend already handles.
The plumbing below is finished before you write a line. All of it is checkable in the public repo.
Database setup
Postgres set up and ready for development: local database, migrations, and typed queries all work out of the box.
Realtime ready on day one
Auth-aware WebSockets already wired. Live updates and collab features become an afternoon of work, not a quarter.

Monorepo that scales
Nx with affected-only builds and shared packages. Two apps, one repo, and you never juggle versions or copy config again.
Strict types across the stack
Zod-validated routes, typed forms, strict TypeScript everywhere. If it compiles, it works.
SDK that writes itself
Backend routes become a typed frontend SDK automatically. Rename a field and the UI breaks at compile time, not in production.

Deploy anywhere
Web and desktop builds from one codebase, CI/CD preconfigured. Ship to any host you like. No platform lock-in, ever.
Feature packs to grow with
Every pack ships real source code: frontend, backend, and admin surfaces where the feature needs them. Add them when you need them, one command each.
Two ways to install features
Same features underneath, different starting point. Either command resolves what the packs depend on, copies the source into your repository, and merges the database schema.
Take a template
A landing page, a design system, a themed layout, and the features already wired into it. Rebrand it, put your product in the middle, ship.
$ hype-stack compose
Compose your own design
Your design and your choices, without rebuilding auth, billing, or notifications. Tick the packs you want and the CLI wires them into the open-source starter.
Questions, answered
Take the free one. Break it on purpose.
Clone it, rename a field, run the typecheck. If that does not convince your developer, nothing on this page will.
free / public / your repo