Skip to Content
QuickstartTanStackTanstack

TanStack Start Quickstart

Create a new Flexkit Studio in a TanStack Start application and run it locally.

Create a new TanStack Start project

Terminal
pnpm create @tanstack/start@latest my-flexkit-app --package-manager pnpm
cd my-flexkit-app

Install Flexkit Studio packages

Terminal
pnpm add @flexkit/studio @flexkit/desk @flexkit/asset-manager @flexkit/explorer lucide-react

Create the Flexkit configuration

Create flexkit.config.tsx in the project root. This file defines your content schema and Studio configuration.

React
flexkit.config.tsx
import { Package, FolderTree } from 'lucide-react';
import { defineConfig, defineEntity } from '@flexkit/studio';
import { AssetManager } from '@flexkit/asset-manager';
import { Desk } from '@flexkit/desk';
import { Explorer } from '@flexkit/explorer';
 
const products = defineEntity({
  name: 'product',
  plural: 'products',
  menu: {
    label: 'Products',
    group: 'catalog',
    icon: <Package />,
  },
  attributes: [
    {
      name: 'name',
      label: 'Product Name',
      scope: 'global',
      dataType: 'string',
      inputType: 'text',
      previewType: 'text',
      isPrimary: true,
      isSearchable: true,
      validation: (z) => z.string().min(1, { message: 'Name is required' }),
      defaultValue: '',
      options: {
        size: 260,
        comment: 'The name of the product',
      },
    },
    {
      name: 'sku',
      label: 'SKU',
      scope: 'global',
      dataType: 'string',
      inputType: 'text',
      isUnique: true,
      isSearchable: true,
      validation: (z) => z.string().min(1, { message: 'SKU is required' }),
      defaultValue: '',
      options: {
        size: 130,
        comment: 'Unique product identifier',
      },
    },
    {
      name: 'description',
      label: 'Description',
      scope: 'global',
      dataType: 'string',
      inputType: 'editor',
      defaultValue: '',
      options: {
        size: 260,
        comment: 'Full product description',
      },
    },
    {
      name: 'price',
      label: 'Price',
      scope: 'global',
      dataType: 'float',
      inputType: 'number',
      previewType: 'text',
      validation: (z) => z.number().min(0, { message: 'Price must be positive' }),
      defaultValue: '',
      options: {
        size: 130,
        comment: 'Product price',
      },
    },
    {
      name: 'category',
      label: 'Category',
      scope: 'relationship',
      dataType: 'string',
      inputType: 'relationship',
      isSearchable: true,
      defaultValue: '',
      relationship: {
        mode: 'single',
        field: 'name',
        entity: 'category',
      },
      options: {
        size: 200,
        comment: 'Product category',
      },
    },
  ],
});
 
const categories = defineEntity({
  name: 'category',
  plural: 'categories',
  menu: {
    label: 'Categories',
    group: 'catalog',
    icon: <FolderTree />,
  },
  attributes: [
    {
      name: 'name',
      label: 'Category Name',
      scope: 'global',
      dataType: 'string',
      inputType: 'text',
      previewType: 'text',
      isPrimary: true,
      isUnique: true,
      isSearchable: true,
      validation: (z) => z.string().min(1, { message: 'Name is required' }),
      defaultValue: '',
      options: {
        size: 200,
        comment: 'The name of the category',
      },
    },
    {
      name: 'slug',
      label: 'URL Slug',
      scope: 'global',
      dataType: 'string',
      inputType: 'text',
      isUnique: true,
      validation: (z) => z.string().min(1, { message: 'Slug is required' }),
      defaultValue: '',
      options: {
        size: 200,
        comment: 'URL-friendly identifier',
      },
    },
    {
      name: 'description',
      label: 'Description',
      scope: 'global',
      dataType: 'string',
      inputType: 'textarea',
      defaultValue: '',
      options: {
        size: 260,
        comment: 'Category description',
      },
    },
  ],
});
 
export default defineConfig([
  {
    title: 'My Studio',
    projectId: 'your-project-id', // Replace with your unique project ID
    basePath: '/studio',
    menuGroups: [
      {
        title: 'Catalog',
        name: 'catalog',
      },
    ],
    plugins: [
      Desk(),
      AssetManager(),
      Explorer(),
      // Add more plugins here as needed
    ],
    schema: [products, categories],
  },
]);
Important: Replace 'your-project-id' with your Flexkit project ID.

Create TanStack Start routes for Studio and API

Create the following files:

      • index.tsx
      • studio.tsx
        • $.tsx
          • $.tsx
React
src/routes/index.tsx
import { createFileRoute, redirect } from '@tanstack/react-router';
 
export const Route = createFileRoute('/')({
  beforeLoad: () => {
    throw redirect({ to: '/studio' });
  },
});
React
src/routes/studio.tsx
import { createFileRoute } from '@tanstack/react-router';
import { FlexkitStudio } from '@flexkit/studio';
import config from '../../flexkit.config';
 
export const Route = createFileRoute('/studio')({
  ssr: false,
  component: StudioPage,
});
 
function StudioPage(): JSX.Element {
  return <FlexkitStudio config={config} />;
}
React
src/routes/studio/$.tsx
import { createFileRoute } from '@tanstack/react-router';
import { FlexkitStudio } from '@flexkit/studio';
import config from '../../../flexkit.config';
 
export const Route = createFileRoute('/studio/$')({
  ssr: false,
  component: StudioPage,
});
 
function StudioPage(): JSX.Element {
  return <FlexkitStudio config={config} />;
}
React
src/routes/api/flexkit/$.tsx
import { createFileRoute } from '@tanstack/react-router';
import { createFlexkitFetchHandler } from '@flexkit/studio/tanstack-start';
 
const flexkitHandler = createFlexkitFetchHandler();
 
export const Route = createFileRoute('/api/flexkit/$')({
  component: () => null,
  server: {
    handlers: {
      GET: async ({ request }) => {
        return flexkitHandler(request);
      },
      POST: async ({ request }) => {
        return flexkitHandler(request);
      },
      PUT: async ({ request }) => {
        return flexkitHandler(request);
      },
      PATCH: async ({ request }) => {
        return flexkitHandler(request);
      },
      DELETE: async ({ request }) => {
        return flexkitHandler(request);
      },
    },
  },
});

Deploy your data schema

Install the Flexkit CLI to deploy your data schema.
flexkit deploy

Run your project

Terminal
pnpm dev

Open your browser and navigate to http://localhost:3000/studio.

Last updated on

© 2026