> For the complete documentation index, see [llms.txt](https://docs.healthuniverse.com/overview/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.healthuniverse.com/overview/building-apps-in-health-universe/developing-your-health-universe-app/working-in-react/typical-project-setup.md).

# Typical Project Setup

A Health Universe React app is an ordinary Node project — there's nothing special about the layout beyond installing the SDK and wiring a few build-time settings so it serves correctly behind a path prefix. The [`react-starter`](https://github.com/Health-Universe/react-starter) repo is a complete worked example; clone it as a starting point.

### Step 1: Create a GitHub Repository

Push your app to a GitHub repository. As with the other runtimes, the repo must be reachable by Health Universe to deploy it.

### Step 2: Repo layout

A typical Vite-based React app looks like:

```
my-clinical-app/
├── package.json          # dependencies + build/start scripts (drives runtime detection)
├── vite.config.js        # base path + optional dev proxy
├── index.html
└── src/
    ├── main.tsx          # mounts <HUProvider> + your app
    ├── HUProvider.tsx     # wraps HealthUniverseProvider (see "Your First App")
    └── …                  # your components, using the SDK hooks
```

`package.json` is the file the platform inspects to identify the runtime. A React (Vite) SPA only needs a `build` script — the platform serves the build output for you, so no `start` script is required:

```json
{
  "name": "my-clinical-app",
  "private": true,
  "scripts": {
    "dev": "vite",
    "build": "vite build"
  },
  "dependencies": {
    "@health-universe/react": "^0.1.0",
    "@tanstack/react-query": "^5.0.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  }
}
```

> A **Next.js or Node** app instead needs a `start` script that listens on the port the platform provides (`PORT`, set to `8501`) — e.g. `"start": "next start -p $PORT"`.

### Step 3: Build & run — static SPA vs Node server

How your app runs on Health Universe depends on the framework, and the platform picks the right mode automatically:

* **React (e.g. Vite)** — built as a **static SPA**. Health Universe runs your `build` step, then serves the static output (`dist/` or `build/`) with a single-page-app fallback. There is no long-running server process, and a `start` script, if present, is ignored.
* **Next.js / Node** — run as a **Node server**. After the build, Health Universe runs `npm run start`, so your `package.json` must expose a `start` script that listens on `PORT` (`8501`). Next.js apps also need `basePath` configured (see Step 5).

### Step 4: Runtime auto-detection

When you deploy, Health Universe inspects your repository and **auto-detects the runtime from `package.json`** (the deploy "main file" is `package.json`; in a monorepo it's `<your-app-folder>/package.json`). You don't choose React/Next.js/Node from a dropdown — the dependencies decide:

* a `next` dependency → **Next.js** (Node server),
* otherwise a `react` / `react-dom` dependency → **React** (static SPA),
* otherwise → a plain **Node** server.

This determines whether the app is served as static assets or run as a Node server.

### Step 5: Base-path handling

Deployed apps are served under a **path prefix**, e.g. `https://apps.healthuniverse.com/<slug>/`, not a dedicated subdomain. For assets and client-side routing to resolve correctly, your build must know that prefix.

The platform injects the prefix at build time under several names so each framework can read it — `VITE_BASE_PATH` (Vite), `NEXT_PUBLIC_BASE_PATH` (Next.js `basePath`), `PUBLIC_URL` (CRA), and a bare `HU_BASE_PATH`. Wire the right one into your build. For Vite:

```js
// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  base: process.env.VITE_BASE_PATH || '/',
  // …plugins, etc.
})
```

#### Client-side routing: strip the trailing slash

If you use a client-side router (React Router, etc.), point its `basename` at the same prefix — **but strip the trailing slash first.** Vite's `base` keeps the trailing slash (`/<slug>/`) because that's correct for asset URLs, but React Router treats a `basename` of `/<slug>/` as *not* matching the no-trailing-slash landing URL `/<slug>` — so the app mounts to a **blank page** even though every asset loaded fine. Strip it so `/<slug>`, `/<slug>/`, and `/<slug>/...` all match:

```tsx
// React Router's basename must NOT carry a trailing slash (Vite's `base` does,
// for assets). Strip it; the `|| '/'` collapse keeps local dev (no prefix) working.
const base = (import.meta.env.VITE_BASE_PATH || '/').replace(/\/+$/, '') || '/'

<BrowserRouter basename={base}>{/* …routes… */}</BrowserRouter>
```

> This is the most common blank-page-after-deploy cause **once you add routing**: assets resolve (correct `base`), but no route matches the landing URL. Don't use `import.meta.env.BASE_URL` for the basename directly — it carries the same trailing slash. Any in-app URLs you build by hand should still use the un-stripped `BASE_URL` so asset paths stay correct.

> When deployed, Health Universe also injects the API origin and account settings (e.g. `VITE_HU_API_URL`, `VITE_CLERK_PUBLISHABLE_KEY`) at build time, so the SDK is configured for you and the signed-in user is already authenticated — no secrets to manage in your repo for the default deployed setup.

### Step 6: Local development against a remote API

To develop against a remote API (staging or a preview) without running a local backend — and without CORS headaches — proxy `/api` through your dev server and point the SDK at the same origin. With Vite:

```js
// vite.config.js
import { defineConfig, loadEnv } from 'vite'

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '')
  return {
    base: process.env.VITE_BASE_PATH || '/',
    server: {
      proxy: {
        '/api': { target: env.VITE_HU_API_PROXY, changeOrigin: true, secure: true },
      },
    },
  }
})
```

Then set `VITE_HU_API_URL=` (empty → same-origin) and `VITE_HU_API_PROXY=https://<staging-host>`, and sign in with the matching Clerk **development** instance (`pk_test_…`).

> If you reinstall the SDK and an import looks stale (`does not provide an export named …`), clear the Vite optimize cache (`rm -rf node_modules/.vite`) and restart the dev server.

### Step 7: Commit and deploy

Commit your code, push to GitHub, then deploy via **Create → Source Code**. See [Deploying to Health Universe](/overview/building-apps-in-health-universe/deploying-your-app-to-health-universe/deploying-to-health-universe.md) for the step-by-step deploy flow.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.healthuniverse.com/overview/building-apps-in-health-universe/developing-your-health-universe-app/working-in-react/typical-project-setup.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
