Studio

A visual interface for your model overrides: list, set, and clear them per feature, and view live SDK usage snippets. Fully responsive — works on desktop and mobile.

Zero-install — served by the SDK router

Recommended

If you already use the Hono or Express router, Studio is served automatically. No separate package, no React app, no extra config. Just mount the router and open the URL.

Hono

typescript
import { Hono } from "hono";
import { createModelKit, createRedisAdapter } from "@benrobo/modelkit";
import { createModelKitHonoRouter } from "@benrobo/modelkit/hono";

const modelKit = createModelKit(
  createRedisAdapter({ url: process.env.REDIS_URL || "redis://localhost:6379" })
);

const app = new Hono();
app.route("/api/modelkit", createModelKitHonoRouter(modelKit));
// Studio is now live at: http://localhost:3000/api/modelkit/studio

Express

typescript
import express from "express";
import { createModelKit, createRedisAdapter } from "@benrobo/modelkit";
import { createModelKitExpressRouter } from "@benrobo/modelkit/express";

const app = express();
app.use(express.json());
const modelKit = createModelKit(
  createRedisAdapter({ url: process.env.REDIS_URL })
);
app.use("/api/modelkit", createModelKitExpressRouter(modelKit));
// Studio is now live at: http://localhost:3000/api/modelkit/studio

Studio is enabled by default. To disable it or change the path:

typescript
createModelKitHonoRouter(modelKit, { studio: false })
createModelKitHonoRouter(modelKit, { studioPath: "/admin/ui" })
// Studio will be at: /api/modelkit/admin/ui

Protecting Studio (auth)

Studio exposes write access to all your overrides — you should protect it in production. Add your own middleware on the mount path before the router:

typescript
// Hono — register middleware on the same path before app.route()
app.use("/api/modelkit/*", async (c, next) => {
  if (c.req.header("Authorization") !== `Bearer ${process.env.MODELKIT_SECRET}`) {
    return c.json({ error: "Unauthorized" }, 401);
  }
  await next();
});

app.route("/api/modelkit", createModelKitHonoRouter(modelKit));
typescript
// Express — pass middleware as a second arg to app.use()
const authGuard = (req, res, next) => {
  if (req.headers.authorization !== `Bearer ${process.env.MODELKIT_SECRET}`) {
    return res.status(401).json({ error: "Unauthorized" });
  }
  next();
};

app.use("/api/modelkit", authGuard, createModelKitExpressRouter(modelKit));

How it works

The Studio UI (React + all dependencies) is bundled into the SDK at build time as a self-contained HTML string. When a request hits /studio, the router serves that HTML directly. No filesystem reads, no external CDN, no React install required in your app.

React component

Optional

If you want to embed Studio directly inside an existing React app (e.g. an internal dashboard), install the package and render the component.

bash
npm install @benrobo/modelkit-studio
# or: bun add @benrobo/modelkit-studio
tsx
import { ModelKitStudio } from "@benrobo/modelkit-studio";
import "@benrobo/modelkit-studio/styles";

function AdminPage() {
  return (
    <ModelKitStudio
      apiUrl="http://localhost:3000/api/modelkit"
      theme="dark"
    />
  );
}

Use your production backend URL for apiUrl — the same route where you mounted createModelKitHonoRouter or createModelKitExpressRouter. Make sure CORS is enabled on the backend if the frontend is on a different origin.

Props

typescript
interface ModelKitStudioProps {
  /** URL of your ModelKit API endpoint (required) */
  apiUrl: string;
  /** Preset theme name or custom theme object (default: "dark") */
  theme?: "light" | "dark" | StudioThemeOverride;
  /** Base theme to merge custom overrides into */
  themeBase?: "light" | "dark";
  /** Additional className for the root container */
  className?: string;
  /** Per-element className overrides */
  classNames?: ClassNameOverrides;
  /** Bring your own TanStack Query client */
  queryClient?: QueryClient;
}

Themes

Built-in presets: dark, light, choco, ocean, sunset, forest, purple, crimson, cyan, amber. Or pass a StudioThemeOverride object for full control.

tsx
import { ModelKitStudio, type StudioThemeOverride } from "@benrobo/modelkit-studio";

const customTheme: StudioThemeOverride = {
  colors: { primary: "#7c3aed", background: "#0c0c0d", text: "#fff" },
  fonts: { body: "Inter", mono: "JetBrains Mono" },
};
<ModelKitStudio apiUrl="..." theme={customTheme} />

Styling

Import @benrobo/modelkit-studio/styles once in your app entry. Studio uses the mk: Tailwind prefix so styles won't clash with your app's own Tailwind classes.

tsx
import "@benrobo/modelkit-studio/styles";

// Override individual element class names
<ModelKitStudio
  classNames={{
    container: "max-w-7xl",
    buttonPrimary: "bg-indigo-600 hover:bg-indigo-500",
  }}
/>