Build managed React applications
Create and operate a browser-only managed React SPA or Contentful App with Brix-owned runtime and Vite integration.
Create a managed React SPA
Create a standalone app:
brix create react-app customer-portal
cd customer-portal
brix dev
From a Brix workspace root, omit --version; the new member uses the workspace's exact Brix version and a bare name is placed under apps/:
brix create react-app customer-portal
brix doctor#customer-portal
brix dev#customer-portal
The generated manifest declares brix.project: "react-application". It has a root index.html, src/main.tsx, src/App.tsx, src/brix.ts, and this Vite configuration:
import { defineBrixReactConfig } from "@brix/react/vite";
export default defineBrixReactConfig();
defineBrixReactConfig configures the managed React JSX runtime, deduplicates React and ReactDOM, supplies browser-safe aliases, and adds the Brix Vitest configuration. Its optional vite value accepts the supported Brix Vite escape hatch as an object or a function of the Vite environment:
export default defineBrixReactConfig({
vite: ({ mode }) => ({
base: mode === "production" ? "/portal/" : "/",
define: { __APP_VARIANT__: JSON.stringify(mode) },
}),
});
Do not replace managed entries, output, JSX settings, or Brix plugins through that escape hatch.
Use the managed runtime
Import React APIs and types from @brix/react, not directly from react. Mount through the client entry point:
import { StrictMode } from "@brix/react";
import { createRoot } from "@brix/react/client";
import { App } from "./App.tsx";
const element = document.getElementById("root");
if (!element) throw new Error("React application root is missing");
createRoot(element).render(
<StrictMode>
<App />
</StrictMode>,
);
The root adapter also exports Brix's React bindings:
useApifor contract-aware requestsuseSignalanduseComputedfor React signal integrationuseStorage,useLocalStorage, anduseSessionStorageTranslationProviderandcreateTranslationHooks- the supported React runtime, hooks, events, elements, and component types
Define browser-safe contracts with defineBrix in src/brix.ts:
import { defineBrix } from "brix/contracts";
export const brix = defineBrix();
export const { createApiContract, executeApi, getPath } = brix;
Application components can then combine project-bound contracts with React hooks:
import { useApi } from "@brix/react";
import { productApiContract } from "@commerce/contracts";
export function Product({ productId }: { productId: string }) {
const request = useApi(productApiContract, {
baseUrl: "https://api.example.com",
});
if (request.isLoading.value) return <p>Loading…</p>;
if (request.isError.value) return <p>Request failed: {request.error.value?.message}</p>;
if (request.data.value) return <h1>{request.data.value.name}</h1>;
return (
<button onClick={() => void request.execute({ params: { productId } })}>Load product</button>
);
}
The contract package is a contextual application dependency: link it in a workspace before importing it. Consult API routes and the API reference for the installed useApi signature.
Understand the application boundary
A managed React application builds once to dist. It is not a Brix server application and has:
- no Hono API or page route implementation
- no SSR,
createBrixApp, or Nodestartcommand - no Preact islands or hydration directives
- no Panda integration; use the React application's chosen CSS approach
- no managed Brix Storybook support
Shared contracts let the React browser call a separately deployed BFF; they do not make the deployments same-origin. Pass that BFF's deployed origin as baseUrl, and configure the BFF to allowlist the browser origin with its CORS middleware. See workspaces and the caching guide.
Create a Contentful App
Use the dedicated preset rather than adding Contentful packages by hand:
brix create contentful-app editorial-tools
Within a workspace:
brix create contentful-app editorial-tools
This remains a react-application, but records the Contentful integration and adds exact compatible SDK, Forma 36, icon, and app-script dependencies. The generated Vite config uses a relative base required by uploaded Contentful assets:
import { defineBrixReactConfig } from "@brix/react/vite";
export default defineBrixReactConfig({ vite: { base: "./" } });
Import the managed surfaces through Brix:
import { useEffect } from "@brix/react";
import { Button, GlobalStyles, Heading } from "@brix/react/contentful";
import { PlusIcon } from "@brix/react/contentful/icons";
import { init, type KnownAppSDK } from "brix/contentful/app";
The generated entry calls init, renders with its SDK, and handles the app configuration location. Preserve base: "./"; brix doctor reports drift. Continue with the Contentful guide.
Continue with integrate an external react host.