GETTING STARTED
Create your first FABRK app in under 5 minutes. Install, configure, build, deploy.
[PREREQUISITES]
- Node.js 22+ — Required runtime. Check with
node --version - pnpm 9+ — Package manager. Install with
npm install -g pnpm - PostgreSQL — Optional. Required for Prisma templates (ai-saas, dashboard)
[STEP 1: SCAFFOLD YOUR APP]
The fastest way to start is with the CLI. It creates a project with FABRK packages pre-configured, a Prisma schema, and a fabrk.config.ts.
npx create-fabrk-app my-app
# You'll be prompted to choose a template:
#
# basic — Clean starting point with core + themes
# ai-saas — AI SaaS with cost tracking, API keys, streaming
# dashboard — Admin dashboard with teams, flags, webhooks, auditcd my-app
pnpm install
pnpm devOpen http://localhost:3000 to see your app running.
pnpm add @fabrk/core @fabrk/config @fabrk/components @fabrk/design-system
# Add feature packages as needed:
pnpm add @fabrk/auth @fabrk/payments @fabrk/ai @fabrk/email
pnpm add @fabrk/storage @fabrk/security @fabrk/store-prisma[STEP 2: PROJECT STRUCTURE]
After scaffolding, your project looks like this:
my-app/
├── src/
│ └── app/
│ ├── layout.tsx # Root layout with providers
│ ├── page.tsx # Home page
│ ├── dashboard/
│ │ └── page.tsx # Dashboard (template-specific)
│ ├── api/
│ │ ├── webhooks/ # Webhook endpoints
│ │ └── keys/ # API key endpoints
│ └── globals.css # CSS variables + design tokens
├── prisma/
│ └── schema.prisma # Database schema (template-specific)
├── fabrk.config.ts # FABRK configuration
├── vite.config.ts # Vite config with fabrk() plugin
├── package.json
├── .env.example # Environment variables
└── tsconfig.json[STEP 3: CONFIGURE FABRK]
Every FABRK app has a fabrk.config.ts at the project root. This is your single source of truth — like vite.config.ts but for your entire application stack.
import { defineFabrkConfig } from '@fabrk/config'
export default defineFabrkConfig({
// Framework runtime
framework: {
runtime: 'vite',
typescript: true,
srcDir: 'src',
database: 'prisma',
},
// Design system
theme: {
system: 'terminal',
colorScheme: 'green',
radius: 'sharp',
},
// Feature flags
notifications: { enabled: true },
teams: { enabled: true, maxMembers: 50 },
featureFlags: { enabled: true },
})defineFabrkConfig() provides full TypeScript autocomplete and Zod validation for all 12 config sections. Defaults are applied automatically — you only configure what you need.[STEP 4: USE COMPONENTS]
Import pre-built components instead of writing them from scratch. All components use design tokens and the terminal aesthetic.
'use client'
import {
KPICard, Card, Badge, Button, DataTable, BarChart
} from '@fabrk/components'
import { cn } from '@/lib/utils'
import { mode } from '@fabrk/design-system'
const stats = [
{ title: 'REVENUE', value: '$12,340', trend: 12.5 },
{ title: 'USERS', value: '1,572', trend: 8.3 },
{ title: 'DEPLOYS', value: '47', trend: -2.1 },
{ title: 'UPTIME', value: '99.9%', trend: 0.1 },
]
export default function DashboardPage() {
return (
<div className="p-6 space-y-6">
{/* KPI row */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
{stats.map((s) => (
<KPICard key={s.title} title={s.title} value={s.value} trend={s.trend} />
))}
</div>
{/* Chart */}
<Card className={cn('p-6 border border-border', mode.radius)}>
<h2 className={cn('text-sm font-bold uppercase mb-4', mode.font)}>
[WEEKLY REVENUE]
</h2>
<BarChart
data={[
{ label: 'Mon', value: 1200 },
{ label: 'Tue', value: 1800 },
{ label: 'Wed', value: 1400 },
{ label: 'Thu', value: 2200 },
{ label: 'Fri', value: 1900 },
]}
/>
</Card>
{/* Status badges */}
<div className="flex gap-2">
<Badge variant="default">[ACTIVE]</Badge>
<Badge variant="secondary">[PENDING]</Badge>
<Button className="ml-auto">{'>'} VIEW ALL</Button>
</div>
</div>
)
}[STEP 5: ADD FEATURES]
Add backend features by installing the relevant package and updating your config. FABRK auto-wires adapters from your configuration.
# Install auth package
pnpm add @fabrk/auth
# Update fabrk.config.ts
auth: {
adapter: 'nextauth',
apiKeys: true,
mfa: true,
config: {
providers: ['google', 'credentials'],
},
}# Install payments package
pnpm add @fabrk/payments
# Update fabrk.config.ts
payments: {
adapter: 'stripe',
mode: 'test',
config: {
webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,
},
}# Install AI package
pnpm add @fabrk/ai
# Update fabrk.config.ts
ai: {
costTracking: true,
validation: 'strict',
providers: ['claude', 'openai'],
budget: { daily: 50, monthly: 1000 },
}[STEP 5B: ADD AN AI AGENT]
AI agents are a first-class primitive in FABRK. Drop an agent.ts file into agents/<name>/ and the framework exposes it automatically as a streaming HTTP endpoint with budget enforcement.
# File-system convention: agents/<name>/agent.ts
# Create agents/assistant/agent.ts
import { defineAgent } from '@fabrk/framework'
export default defineAgent({
model: 'claude-sonnet-4-6',
systemPrompt: 'You are a helpful coding assistant. Be concise.',
stream: true,
memory: true,
auth: 'none',
budget: { daily: 5.0, perSession: 0.50 },
})
# The agent is automatically available at POST /api/agents/assistant'use client'
import { useAgent } from '@fabrk/framework/client'
function ChatPage() {
const { messages, send, isStreaming } = useAgent('assistant')
return (
<div>
{messages.map((m, i) => (
<div key={i}>{m.role}: {m.content}</div>
))}
<form onSubmit={(e) => { e.preventDefault(); send(new FormData(e.currentTarget).get('msg') as string) }}>
<input name="msg" placeholder="Ask something..." />
<button type="submit" disabled={isStreaming}>> SEND</button>
</form>
</div>
)
}budget field sets hard limits per agent — daily caps total spend across all sessions in a 24-hour window, perSession caps a single conversation. Requests that would exceed either limit are rejected before hitting the LLM provider.[STEP 5C: ADD TOOLS]
Tools extend what agents can do. Drop a tool.ts file into tools/<name>/, then reference it by name in any agent definition.
# File-system convention: tools/<name>/tool.ts
# Create tools/search-docs/tool.ts
import { defineTool } from '@fabrk/framework'
export default defineTool({
name: 'search-docs',
description: 'Search project documentation for answers.',
schema: {
type: 'object',
properties: {
query: { type: 'string', description: 'Search query' },
},
required: ['query'],
},
handler: async ({ query }) => ({
content: [{ type: 'text', text: `Results for: ${query}` }],
}),
})# Then reference it in your agent:
export default defineAgent({
model: 'claude-sonnet-4-6',
tools: ['search-docs'],
// ...
})tools/ directory at startup. Any file matching tools/*/tool.ts is registered automatically — no manual imports or plugin registration required.[STEP 5D: AGENT MEMORY AND TESTING]
Agents with memory: true persist conversation history automatically. The built-in testing framework lets you mock LLM responses and assert on tool calls without making real API requests.
import { createTestAgent, mockLLM, respondedWith } from '@fabrk/framework/testing'
const agent = createTestAgent('assistant', {
mock: mockLLM().onMessage('hello').respondWith('Hi there!'),
})
const result = await agent.send('hello')
expect(respondedWith(result, /Hi there/)).toBe(true)[STEP 6: AUTO-WIRE AND RUN]
FABRK's autoWire() reads your config and creates all adapters automatically. In development, applyDevDefaults() fills in sensible defaults so you can run without any API keys.
import { autoWire, applyDevDefaults } from '@fabrk/core'
import config from '../../fabrk.config'
// In development: auto-fills console email, local storage, memory stores
const devConfig = process.env.NODE_ENV === 'development'
? applyDevDefaults(config)
: config
// Creates all adapters from config
export const fabrk = autoWire(devConfig)
// Access adapters
export const { email, storage, payments, auth } = fabrk[STEP 7: DATABASE WITH PRISMA]
If your template includes Prisma, set up your database:
# Set your database URL
echo 'DATABASE_URL="postgresql://user:pass@localhost:5432/myapp"' >> .env
# Push schema to database
pnpm dlx prisma db push
# Generate client
pnpm dlx prisma generateUse @fabrk/store-prisma to connect FABRK's stores to your database:
import { autoWire } from '@fabrk/core'
import { PrismaTeamStore, PrismaAuditStore } from '@fabrk/store-prisma'
import { PrismaClient } from '@prisma/client'
const prisma = new PrismaClient()
// Inject Prisma stores via StoreOverrides
const fabrk = autoWire(config, undefined, {
teamStore: new PrismaTeamStore(prisma),
auditStore: new PrismaAuditStore(prisma),
})[STEP 8: DEPLOY]
Deploy to Vercel, Railway, or any Node.js host:
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel
# Set environment variables
vercel env add DATABASE_URL
vercel env add NEXTAUTH_SECRET
vercel env add STRIPE_SECRET_KEYfabrk.config.ts:- Set
payments.mode: 'live' - Set
email.adapter: 'resend'(not console) - Enable
security.headers: truefor HSTS + CSP - Configure rate limiting with Upstash Redis
- Enable audit logging for compliance
[USING THE CLI]
The fabrk CLI helps with development workflows:
# Start Vite dev server with FABRK tooling
fabrk dev
# Build for production (client + SSR)
fabrk build
# Start production server
fabrk start
# Show project info (agents, tools, prompts)
fabrk info
# List all discovered agents
fabrk agents
# Run health check
fabrk check
# Run agent tests
fabrk test[NEXT STEPS]
create-fabrk-app and the fabrk dev CLI.