1. Hello World, with a real entry point
We will build tic-tac-toe: two authenticated players, one shared board, and a server that decides whether each move is legal. Start with a page, not the whole game.
Download the complete project below, extract it into a new directory, then run:
npm ci
npm run helloUse Node 22.13 or newer. Visit http://localhost:8181. You should see “Hello world!”. Stop this checkpoint with Ctrl+C before running the next one.
import { defineApp, page } from 'redweb';
@page('/', { live: false })
class HomePage {
render() { return <h1>Hello world!</h1>; }
}
const app = defineApp({ pages: [HomePage] });
await app.run();@page('/') connects a class to a URL. render() returns TSX, which Redweb turns into HTML on the server. live: false means this page needs no live socket. defineApp gathers the application's parts; run() opens the listener.
Think of the page class as a recipe for a document. The browser receives the baked document, not a React application or the server's TypeScript.
Why the entry point is so small
This project's package.json contains "type": "module". Its compiler configuration extends redweb/tsconfig.json. That combination enables Redweb JSX, decorators, and top-level await:
{
"extends": "redweb/tsconfig.json",
"compilerOptions": { "rootDir": "src", "outDir": "dist", "sourceMap": true },
"include": ["src/**/*.ts", "src/**/*.tsx"]
}You can still handle Promise failures as usual. The introduction does not need to demonstrate every error-handling or deployment option at once. The downloaded README explains port selection, template roots, signals, and the more configurable game factory used by tests.
Checkpoint: the page renders through an actual Node HTTP listener, with no browser framework. To add another page later, declare another decorated class and pass pages: [HomePage, AboutPage].
Download the complete project Setup, optional configuration, and limits