typeway v0 — coming soon Capabilities Build log Get notified GitHub ↗

One predictable shape for every TypeScript app.

Fullstack from day one. Fewer architectural decisions. Predictable code for humans and agents — under one CLI and one set of conventions. Agents know what to write. Humans know how to review. Everything underneath remains yours.

Proven libraries, one coherent framework — Bun · Elysia · Vite · TypeBox

The shape, demonstrated.

A generated project rather than a description of one — same layout every time, documented for a person, an agent, and a compiler.

Click a file or a tab — 13 work too. The terminal is live.

storefront — created with typeway new main · bun 1.4
zsh — ~/code CLI preview

            
# AGENTS.md

Every Typeway app ships this file. It is written for the tools that
write code here, and it is generated — not maintained by hand.

## Layout

app/           domain logic. models, context, use cases.
config/        typed configuration. env is validated at boot.
db/            schema and migrations. one table per file.
server/        http. elysia routes, middleware, the app instance.
src/           frontend. src/server.ts is the SSR entry — the
               name is load-bearing, do not rename it.
tests/         integration tests. unit tests live beside sources.

## Rules

- Models are app/models/<singular>.ts and export queries, never a
  bare table. The table lives in db/schema/.
- Database access goes through getDb(), which resolves the
  request scope. Never import the connection directly.
- Validation is TypeBox everywhere: request schemas, config, models.
  Do not add a second validation library.
- Routes are registered on the Elysia app; anything unmatched is the
  frontend's. Do not add a catch-all route.

## Commands

  bun run dev          api + ssr + hmr, one process
  bun run build        client, ssr and server bundles
  bun test             unit and integration
  typeway generate     scaffolds code and the docs for it

## When you add a capability

Run typeway add <name> rather than wiring it by hand. It writes the
integration, the conventions section in this file, and a skill — so the
next agent starts where you finished.
// The one SSR entry. Dev and production run this exact module.
import { connect } from "@typeway/connect";
import { app } from "../server/app";
import { createServer } from "vite";

const dev = process.env.NODE_ENV !== "production";

if (dev) {
  const vite = await createServer({
    server: { middlewareMode: true },
  });

  // Registered routes never reach the bridge — Elysia's router
  // gives them precedence over the wildcard connect() mounts.
  app.use(
    connect(vite.middlewares, {
      fallback: async (request) => {
        const { default: ssr } = await vite.environments.ssr.runner
          .import("./src/server.ts");
        return ssr.fetch(request);
      },
    }),
  );
} else {
  // The build emits a fetch-native handler, so production mounts it
  // directly (~0.4 µs) instead of paying for a bridge round-trip.
  app.mount(await loadBuiltHandler());
}

app.listen(3000);
● v0 — not released main bun 1.4 · elysia 2.0 · vite 8 3 tabs open · 0 problems

Easy for agents to write. Easy for humans to review.

Typeway gives every change a familiar shape. Agents follow deterministic, greppable conventions, while generated guidance keeps intent next to implementation — so reviewers can focus on behavior instead of reconstructing how the project is organized.

Everything you need.

A full-stack framework with strong conventions for every part of your application.

From generator to page.

  1. 01

    Generate the model

    One command scaffolds the table, the domain model, and the docs for both.

    $ typeway generate model article
     db/schema/article.ts
     app/models/article.ts
     AGENTS.md  # documented where the next agent will look
  2. 02

    Model the domain

    Queries live with the model. The table stays in db/schema/. Validation is TypeBox.

    export const Article = {
      recent: () => getDb().query.articles.findMany({
        orderBy: (t, { desc }) => desc(t.createdAt),
        limit: 25,
      }),
      create: (input: Static<typeof ArticleInput>) =>
        getDb().insert(articles).values(input).returning(),
    };
  3. 03

    Expose an API route

    Elysia handlers stay thin. Params and bodies are typed once and shared with the client.

    app.get("/api/articles", () => Article.recent())
      .post("/api/articles", ({ body }) => Article.create(body), {
        body: ArticleInput,
      });
  4. 04

    Render the page

    Same request scope reaches the database from SSR — no second data layer to invent.

    export const Route = createFileRoute("/articles")({
      loader: () => Article.recent(),
      component: ArticlesPage,
    });
  5. 05

    Leave instructions for the next agent

    Generators write the knowledge to maintain what they just wrote — so the next edit starts where this one finished.

    # from AGENTS.md — generated, not hand-maintained
    - Models are app/models/<singular>.ts and export queries, never a bare table.
    - Database access goes through getDb(), which resolves the request scope.
    - Validation is TypeBox everywhere. Do not add a second validation library.

Build log

Written as a log rather than a promise: what shipped, on what day, and what it cost. Everything not started yet is at the bottom, where it belongs.

Started 27 Jun 2026 Last shipped 10 Aug 2026 Status v0, in development License MIT
2026
Now

Building The CLI

typeway new, generate, add, db and console — the terminal tab above is what it will feel like. Generators write the code and the docs for that code in the same pass: an AGENTS.md section and a skill land next to every file they scaffold.

Now

Building Models and domain

A domain layer with conventions for structure, relations, migrations, seeds and factories, so a model is a file in a known place rather than a decision. Built on whichever ORM you like — Drizzle is the default because it is the thinnest, but the conventions are the part Typeway ships, so the ORM underneath stays yours to swap.

10 Aug

Shipped The backend and the frontend's server can share things

AsyncLocalStorage gives every incoming request its own scope, so your API routes and the server-rendering half of your frontend reach the same database handle, the same open transaction and the same current user — without threading any of it through every function call. One request, one context, both sides of the app.

98a61f8 · #7 · unit tests for the scope, integration tests for API + SSR
3 Aug

Shipped Production stops going through the bridge

The built SSR handler is fetch-native, so production mounts it directly on Elysia (.mount(), ~0.4 µs) instead of paying for a Connect round-trip, and the client build is registered as static routes at boot. The bridge is now what it should always have been: a dev-mode component for Vite.

b081c55
31 Jul

Shipped Paired A/B benchmarks

Not "Typeway does N req/s" — every arm is measured back to back against its own baseline on one machine, interleaved round by round, median by RPS. The question was what the glue costs.

scenarioratioΔ µs/req
registered route, bridge mounted0.985×+0.2
SSR via connect() fallback1.010×−2.0
static asset, prod path0.995×+0.2
bare bridge round-trip (GET) — dev only0.485×+10.6

The last row is the honest one, and it only ever happens in development: a bridge hop costs ~10 µs, which is most of a request that does nothing and none of a request that does something. Production never touches the bridge — the built handler is mounted straight onto Elysia.

2226b7b
31 Jul

Shipped Kitchen-sink fixture app

One route per TanStack feature that crosses HTTP — streaming SSR, server functions, redirects, notFound(), cookies, multipart, SSE, binary assets — tested against both the dev server and a production build, because they are different failure surfaces.

dee676a
31 Jul

Shipped Integration suite, CI, and a compatibility matrix

The smoke checks became a real suite that boots the actual dev and production servers. A scheduled job re-runs it against the latest Bun, Elysia, Vite and TanStack, so upstream drift shows up as a red build instead of as a surprise.

eef0dd1
31 Jul

Shipped @typeway/connect — Vite under Elysia

The first real piece: run Connect/Express middleware inside an Elysia app, mounted as a wildcard route so registered routes never touch it. Raw streamed request bodies, streaming responses, multiple Set-Cookie values preserved, null bodies for 204/304. Zero runtime dependencies, and that is a constraint we intend to keep.

4c74808 → f5956cf
27 Jun

Shipped init

One commit: a README and an opinion.

dac9f57

Not started yet

designed, in the umbrella, waiting their turn
Next

Planned Auth, jobs, mailers

typeway add auth over better-auth. A Postgres-backed job queue, because most apps never needed Redis. react-email templates with adapters and dev previews.

Next

Planned Realtime, storage, caching

Elysia websockets with channel conventions. A thin layer over Bun's native S3 client. A database-backed cache with Redis as an opt-in, not a prerequisite.

Next

Planned Testing, security defaults, observability

Factories and request specs through Eden, type-checked against your routes. CORS, secure headers and rate limiting on from the first request. Structured logging and OpenTelemetry as a convention rather than a weekend project.

Next

Planned One-binary deploys

bun --compile, copy it to a box, run it.

Be there for v0.

One email when bun create typeway actually works — no drip campaign, no countdown. The build log keeps moving either way.