Skip to content

Zero to a working route in under five minutes.

Create a Project ​

sh
npm create kosmo demo

A short interactive setup walks you through the choices that matter: the frontend framework and the backend you want to build with. Everything else starts with sensible defaults.

Pick whatever feels familiar - nothing here is set in stone, and any folder you add later can make entirely different choices.

It is also possible to bootstrap in the current folder, just use . as name:

sh
npm create kosmo .

After bootstrap, cd into freshly created project (unless the project was bootstrapped in the current folder):

sh
cd ./demo

Install Dependencies ​

sh
npm install

The scaffold is complete, not a skeleton - everything comes filled in. What it doesn't have yet is routes, and that is what you add next.

Start the dev server ​

The dev server watches your routes and recomputes as you work - and seeds starter code into any route or page file you create empty:

sh
npm run dev

Your app is now running at http://localhost:4556.

Create a route ​

Create the file api/users/[id]/index.ts - KosmoJS detects it and seeds starter code automatically.

Replace the seeded content with something real:

ts
// Hono: api/users/[id]/index.ts
import { defineRoute } from "_/api";

export default defineRoute<"users/[id]">(({ GET }) => [
  GET(async (ctx) => {
    const { id } = ctx.req.param();
    return ctx.json({ id, name: "Jane Smith", email: "jane@example.com" });
  }),
]);

Visit http://localhost:4556/api/users/123. You should see JSON.

Create a page ​

With the dev server still running, create pages/users/[id]/index.tsx (or .vue / .svelte / .mdx). KosmoJS seeds a placeholder component - replace it with a page that fetches from your API route. React, SolidJS, and Vue fetch in the component here; Svelte and MDX read through a loader export instead (resolved before render), so they need no loading state:

tsx
// React: pages/users/[id]/index.tsx
import { useState, useEffect } from "react";
import { useParams } from "react-router";
import fetchClients from "_/fetch";

const { GET } = fetchClients["users/[id]"];

export default function UserPage() {
  const { id } = useParams();
  const [user, setUser] = useState(null);

  useEffect(() => { GET([id]).then(setUser); }, [id]);

  return user
    ? <div><h1>{user.name}</h1><p>{user.email}</p></div>
    : <div>Loading...</div>;
}

Visit http://localhost:4556/users/123. Your page renders with data from the API.

The fetch client is fully typed - user.name and user.email autocomplete in your editor, and invalid parameters are caught before the request leaves the browser.

What just happened ​

Your folder structure became your routes:

api/users/[id]/index.ts     ->  /api/users/:id
pages/users/[id]/index.tsx  ->  /users/:id

[id] is a required parameter. {id} makes it optional. {...path} matches any depth. The parallel structure between api/ and pages/ is intentional - API endpoints and their corresponding pages are always easy to find.

The fetch client is derived automatically from your API route definition. Change the API types, and the client updates with them - no manual sync.


That's the foundation. From here:

  • Tutorial - validation, middleware, fetch clients, pages, SSR
  • Project Structure - what lives where, and what @/ ~/ _/ mean
  • Configuration - every kosmo.config.ts option
  • CLI - every command and flag, interactive and non-interactive
  • Routing - parameters, mixed segments, power syntax
  • Framework Support - what each framework does and doesn't support
  • Features - everything KosmoJS provides, at a glance

Released under the MIT License.