Next.js Quickstart
Create a new Flexkit Studio in a Next.js application and run it locally.
Before you start
Use Node.js 22 or later and a package manager. Create a Flexkit project, copy its Project ID, and ensure your account can deploy its schema. These examples use a project you can safely populate with synthetic data.
Keep the generated application’s package versions locked. See compatibility when upgrading. Use the directory layout shown here; adjust relative imports if you choose a src directory in Next.js.
Create a new Next.js project
pnpm
pnpm create next-app@latest my-flexkit-app --yes
cd my-flexkit-appnpm
npx create-next-app@latest my-flexkit-app --yes
cd my-flexkit-appyarn
yarn create next-app@latest my-flexkit-app --yes
cd my-flexkit-appbun
bun create next-app@latest my-flexkit-app --yes
cd my-flexkit-appInstall Flexkit Studio packages
pnpm
pnpm add @flexkit/studio @flexkit/desk @flexkit/asset-manager @flexkit/explorer @flexkit/ainpm
npm install @flexkit/studio @flexkit/desk @flexkit/asset-manager @flexkit/explorer @flexkit/aiyarn
yarn add @flexkit/studio @flexkit/desk @flexkit/asset-manager @flexkit/explorer @flexkit/aibun
bun add @flexkit/studio @flexkit/desk @flexkit/asset-manager @flexkit/explorer @flexkit/aiCreate the Flexkit configuration
Create a flexkit.config.ts file in the root of your project. This file defines the project schema used by the CLI. The separate Studio configuration below registers browser extensions.
import { defineConfig, defineEntity } from '@flexkit/studio';
const categories = defineEntity({
name: 'category',
plural: 'categories',
display: 'name',
menu: { label: 'Categories' },
attributes: [
{ name: 'name', label: 'Name', scope: 'local', dataType: 'string', inputType: 'text', searchable: true },
{ name: 'slug', label: 'Slug', scope: 'global', dataType: 'string', inputType: 'text', unique: true },
],
});
const products = defineEntity({
name: 'product',
plural: 'products',
display: 'name',
menu: { label: 'Products' },
attributes: [
{ name: 'name', label: 'Name', scope: 'local', dataType: 'string', inputType: 'text', searchable: true },
{
name: 'sku',
label: 'SKU',
scope: 'global',
dataType: 'string',
inputType: 'text',
unique: true,
searchable: true,
},
{ name: 'price', label: 'Price', scope: 'local', dataType: 'float', inputType: 'number' },
{ name: 'image', label: 'Image', scope: 'global', dataType: 'asset', inputType: 'asset' },
{ name: 'status', label: 'Status', scope: 'global', dataType: 'string', inputType: 'text', defaultValue: 'draft' },
{
name: 'category',
label: 'Category',
scope: 'relationship',
dataType: 'string',
inputType: 'relationship',
relationship: { mode: 'single', field: 'name', entity: 'category' },
},
],
});
export default defineConfig({
title: 'Catalog Studio',
projectId: 'your-project-id',
basePath: '/studio',
scopes: [{ name: 'default', label: 'Default', isDefault: true }],
schema: [products, categories],
});Keep this configuration free of browser extension imports so the CLI can load it. Create a separate Studio configuration:
import { defineConfig } from '@flexkit/studio';
import { Desk } from '@flexkit/desk';
import { AssetManager } from '@flexkit/asset-manager';
import { Explorer } from '@flexkit/explorer';
import { AI } from '@flexkit/ai';
import project from './flexkit.config';
export default defineConfig({
...project,
extensions: [Desk(), AssetManager(), Explorer(), AI()],
});Important: Replace 'your-project-id' with the unique project ID of your Flexkit project.
local fields like product names, descriptions, prices, and category labels use the currently selected scope in Studio. If a local field has no value in the selected scope, the default scope value is used.
Create the API route handler and Studio page
Create a new API route handler to serve the Flexkit API and a Studio page to render the Flexkit Studio interface. Create the following file structure:
- route.ts
- page.tsx
import { createFlexkitApiHandler } from '@flexkit/studio/nextjs';
import { NextResponse } from 'next/server';
import { cookies, headers } from 'next/headers';
const flexkitHandler = createFlexkitApiHandler({
NextResponse,
cookies,
headers,
});
export const runtime = 'nodejs';
export const { GET, POST, PUT, PATCH, DELETE } = flexkitHandler;
import { JSX } from 'react';
import '@flexkit/studio/styles.css';
import '@flexkit/desk/styles.css';
import '@flexkit/asset-manager/styles.css';
import '@flexkit/explorer/styles.css';
import '@flexkit/ai/styles.css';
import { FlexkitStudio } from '@flexkit/studio';
import config from '../../../flexkit.studio';
export default function Page(): JSX.Element | null {
return <FlexkitStudio config={config} />;
}Deploy your data schema
flexkit login
flexkit whoami
flexkit deployRun Your Project
Start the development server:
pnpm
pnpm devnpm
npm run devyarn
yarn devbun
bun devOpen your browser and navigate to http://localhost:3000/studio
Confirm your first success
Sign into Studio with the account that has access to the configured project. Open Desk, create a Category and Product, save, and reopen the record. Open Explorer and run the tutorial read. The record ID and global SKU should agree with the saved record.
If the UI loads but data does not, check the project ID, completed schema deployment, role/spaces, and API handler route. Missing styles usually indicate an omitted extension stylesheet. Continue with your first workflow, then production deployment.