Getting Started

Scaffold a project or drop hadars into an existing React app.

Scaffold a new project

Creates a project with TypeScript and Tailwind already wired in:

npx hadars new my-app
cd my-app
npm install
npm run dev

Manual installation

Add hadars to an existing project:

npm install hadars

1 — hadars.config.ts

Create a config file at the root of your project. The only required field is entry:

import type { HadarsOptions } from 'hadars';

const config: HadarsOptions = {
    entry: 'src/App.tsx',
    port: 3000,
};

export default config;

For a multi-core production server:

import os from 'os';
import type { HadarsOptions } from 'hadars';

const config: HadarsOptions = {
    entry: 'src/App.tsx',
    port: 3000,
    workers: os.cpus().length,
};

export default config;

2 — src/App.tsx

Export a default React component and an optional getInitProps function. Place HadarsHead anywhere in the tree — no wrapper component needed.

import React from 'react';
import {
    HadarsHead,
    type HadarsApp,
    type HadarsRequest,
} from 'hadars';

interface Props {
    user: { name: string; email: string };
}

const App: HadarsApp<Props> = ({ user }) => (
    <>
        <HadarsHead status={200}>
            <title>Hello {user.name}</title>
            <meta name="description" content="My hadars app" />
        </HadarsHead>
        <main>
            <h1>Hello, {user.name}!</h1>
            <p>{user.email}</p>
        </main>
    </>
);

// Runs on the server for every request.
export const getInitProps = async (req: HadarsRequest): Promise<Props> => {
    const user = await db.getUser(req.cookies.session);
    return { user };
};

export default App;

Static files

Place images, fonts, favicons, robots.txt, and any other static assets in a static/ directory at your project root. hadars serves them automatically — no config needed.

my-app/
├── static/
│   ├── logo.png
│   ├── favicon.ico
│   └── robots.txt    # served at /robots.txt
├── src/
│   └── App.tsx
└── hadars.config.ts

3 — CLI

# Development server with React Fast Refresh HMR
hadars dev

# Production build — client + SSR compiled in parallel
hadars build

# Serve the production build
hadars run

# Bundle into a single self-contained Lambda .mjs
hadars export lambda [output.mjs]

HadarsRequest

The request object passed to getInitProps extends the standard Request with:

interface HadarsRequest extends Request {
    pathname: string;               // e.g. "/blog/my-post"
    search: string;                 // e.g. "?page=2"
    location: string;               // pathname + search
    cookies: Record<string, string>;
}

Lifecycle hooks

Beyond getInitProps, you can optionally export:

ExportRuns onPurpose
getInitPropsserverFetch data from the incoming request. Return props passed to the app component.
getFinalPropsserverStrip server-only fields before props are serialised into the page JSON for the client.
getClientPropsclientEnrich props with browser-only data (localStorage, device APIs) after the page loads.
export const getFinalProps = async ({ secret, ...props }: Props) => {
    // "secret" will not appear in the client bundle's JSON payload
    return props;
};

export const getClientProps = async (props: PublicProps) => {
    return {
        ...props,
        theme: localStorage.getItem('theme') ?? 'dark',
    };
};