Overview

Getting Started

Requirements

  • Node.js 20.19 or newer.
  • A package manager: pnpm or npm.

The examples below use pnpm. If you prefer npm, choose npm in the generator and use the matching install and run commands.

Create an app

Run the project generator with the basic template:

npx @reckona/create-mreact-app my-app --template basic --src-dir
cd my-app
pnpm install
pnpm dev

Open the local URL printed by the dev server. It defaults to http://127.0.0.1:3001 unless PORT, --port, or vite.config.ts changes it.

The generator can also prompt for the package manager, template, src/app layout, and deploy target:

npx @reckona/create-mreact-app

Choose a starter or deployment target when you already know the shape you want:

npx @reckona/create-mreact-app my-app --template tailwind --src-dir
npx @reckona/create-mreact-app my-app --template basic --src-dir --deploy cloudflare
npx @reckona/create-mreact-app my-app --template basic --src-dir --deploy container
npx @reckona/create-mreact-app my-app --template basic --src-dir --deploy aws-lambda
npx @reckona/create-mreact-app my-dashboard --template dashboard

Upgrade an existing generated app with a dry run first:

npx @reckona/create-mreact-app upgrade --dry-run
npx @reckona/create-mreact-app upgrade

What was generated

With --src-dir, routes live in src/app, shared application code starts in src/lib, and public assets live in public. The basic template now starts with a small counter app:

my-app/
  src/
    app/
      layout.tsx
      page.tsx
    lib/
      app-info.ts
  public/
  vite.config.ts
  tsconfig.json
  package.json

The generated vite.config.ts wires the Mreact router plugin to those paths as an ESM config. The generated tsconfig.json includes Node types for that config and app-router global types so route layouts can use <Slot /> without adding a local import. The generated package.json includes scripts for development, production build, type checking, linting, tests, and production serving.

Try the counter

Open the local URL and click +1. The generated home page is a counter starter that uses cell for client interactivity while still keeping the route file in the app router.

The --src-dir starter renders src/app/page.tsx with a title from src/lib/app-info.ts:

import { cell } from "@reckona/mreact-reactive-core";
import { appTitle } from "../lib/app-info.js";

export const metadata = {
  title: "Counter",
};

export default function Page() {
  const count = cell<number>(0);

  return (
    <main>
      <h1>{appTitle}</h1>
      <p>
        Count: <strong>{count.get()}</strong>
      </p>
      <p>
        <button type="button" onClick={() => count.set((value) => value + 1)}>
          +1
        </button>{" "}
        <button type="button" onClick={() => count.set(0)}>
          Reset
        </button>
      </p>
    </main>
  );
}

Add a route

Add a second page at src/app/docs/page.tsx to create /docs/:

export const metadata = {
  title: "Docs",
  description: "A server-rendered route.",
};

export default function Page() {
  return (
    <main>
      <h1>Docs</h1>
      <p>This page is another server-rendered route.</p>
    </main>
  );
}

When the dev server is running, visit /docs/ to confirm the route was picked up.

Check the project

Before treating the app as production-ready, run the generated verification scripts:

pnpm typecheck
pnpm lint
pnpm test
pnpm build

The build script writes production output to .mreact. Treat that directory as generated deployment material.

Start production output

pnpm start

pnpm start serves the built .mreact output with the Node adapter. For local request summaries, run mreact-router dev --log=requests during development or mreact-router start .mreact --log=requests after a build.

Next steps