Comprehensive Zod schemas for configuration and registry validation. Provides runtime validation with TypeScript type inference for all configuration files, registry items, and API responses.
Schemas for validating configuration files and settings.
Validates single registry configuration. Supports both simple string URLs and advanced objects with authentication.
const registryConfigItemSchema: z.ZodUnion<[
z.ZodString, // Simple: "https://example.com/{name}.json"
z.ZodObject<{
url: z.ZodString // Must include {name} placeholder
params?: Record<string, string>
headers?: Record<string, string>
}>
]>Simple Format: String URL with {name} placeholder
Advanced Format: Object with URL, query params, and headers for authentication
Usage Example:
import { registryConfigItemSchema } from 'shadcn/schema';
// Validate simple string format
const simple = registryConfigItemSchema.parse(
'https://registry.example.com/{name}.json'
);
// Validate advanced format with auth
const advanced = registryConfigItemSchema.parse({
url: 'https://registry.example.com/{name}.json',
headers: {
'Authorization': 'Bearer ${API_TOKEN}'
},
params: {
'version': 'latest'
}
});Validates registry configuration object. Maps registry namespaces to their configurations.
const registryConfigSchema: z.ZodRecord<
z.ZodString, // Key must start with @ (e.g., "@v0", "@acme")
typeof registryConfigItemSchema
>Usage Example:
import { registryConfigSchema } from 'shadcn/schema';
const config = registryConfigSchema.parse({
'@shadcn': 'https://ui.shadcn.com/r/{name}.json',
'@acme': {
url: 'https://acme.com/registry/{name}.json',
headers: {
'Authorization': 'Bearer ${ACME_TOKEN}'
}
}
});Validates raw components.json configuration before path resolution.
const rawConfigSchema: z.ZodObject<{
$schema?: string
style: string
rsc: boolean // Default: false
tsx: boolean // Default: true
tailwind: {
config?: string
css: string
baseColor: string
cssVariables: boolean // Default: true
prefix?: string // Default: ""
}
iconLibrary?: string
menuColor?: "default" | "inverted" // Default: "default"
menuAccent?: "subtle" | "bold" // Default: "subtle"
aliases: {
components: string
utils: string
ui?: string
lib?: string
hooks?: string
}
registries?: RegistryConfig
}>Usage Example:
import { rawConfigSchema } from 'shadcn/schema';
const config = rawConfigSchema.parse({
style: 'new-york',
rsc: false,
tsx: true,
tailwind: {
css: 'app/globals.css',
baseColor: 'slate',
cssVariables: true
},
aliases: {
components: '@/components',
utils: '@/lib/utils'
}
});Validates resolved configuration with paths. Extends rawConfigSchema with resolved absolute paths.
const configSchema: z.ZodObject<{
// All fields from rawConfigSchema
// Plus:
resolvedPaths: {
cwd: string
tailwindConfig: string
tailwindCss: string
utils: string
components: string
lib: string
hooks: string
ui: string
}
}>Usage Example:
import { configSchema, type Config } from 'shadcn/schema';
const config: Config = configSchema.parse({
style: 'new-york',
rsc: false,
tsx: true,
tailwind: {
css: 'app/globals.css',
baseColor: 'slate',
cssVariables: true
},
aliases: {
components: '@/components',
utils: '@/lib/utils',
ui: '@/components/ui'
},
resolvedPaths: {
cwd: '/project',
tailwindConfig: '/project/tailwind.config.js',
tailwindCss: '/project/app/globals.css',
utils: '/project/lib/utils',
components: '/project/components',
ui: '/project/components/ui',
lib: '/project/lib',
hooks: '/project/hooks'
}
});Validates workspace/monorepo configuration. Maps workspace keys to their configurations.
const workspaceConfigSchema: z.ZodRecord<string, typeof configSchema>Usage Example:
import { workspaceConfigSchema } from 'shadcn/schema';
const workspaceConfig = workspaceConfigSchema.parse({
'apps/web': {
style: 'new-york',
/* ... config ... */
resolvedPaths: { /* ... */ }
},
'apps/docs': {
style: 'default',
/* ... config ... */
resolvedPaths: { /* ... */ }
}
});Schemas for validating registry items and their components.
Enum of valid registry item types.
const registryItemTypeSchema: z.ZodEnum<[
"registry:lib",
"registry:block",
"registry:component",
"registry:ui",
"registry:hook",
"registry:page",
"registry:file",
"registry:theme",
"registry:style",
"registry:item",
"registry:base",
"registry:font",
"registry:example", // Internal use only
"registry:internal" // Internal use only
]>Usage Example:
import { registryItemTypeSchema } from 'shadcn/schema';
const type = registryItemTypeSchema.parse('registry:ui');Validates registry item file. Discriminated union based on type.
const registryItemFileSchema: z.ZodDiscriminatedUnion<"type", [
// registry:file and registry:page require target
z.ZodObject<{
path: string
content?: string
type: "registry:file" | "registry:page"
target: string // Required
}>,
// Other types have optional target
z.ZodObject<{
path: string
content?: string
type: RegistryItemType // Excluding file and page
target?: string
}>
]>Usage Example:
import { registryItemFileSchema } from 'shadcn/schema';
// UI component file
const componentFile = registryItemFileSchema.parse({
path: 'components/ui/button.tsx',
content: 'export function Button() { /* ... */ }',
type: 'registry:ui'
});
// Page file with required target
const pageFile = registryItemFileSchema.parse({
path: 'app/dashboard/page.tsx',
content: 'export default function Dashboard() { /* ... */ }',
type: 'registry:page',
target: 'app/dashboard/page.tsx'
});Validates Tailwind configuration for registry item.
const registryItemTailwindSchema: z.ZodObject<{
config?: {
content?: string[]
theme?: Record<string, any>
plugins?: string[]
}
}>Usage Example:
import { registryItemTailwindSchema } from 'shadcn/schema';
const tailwind = registryItemTailwindSchema.parse({
config: {
content: ['./components/**/*.tsx'],
theme: {
extend: {
colors: {
border: 'hsl(var(--border))'
}
}
},
plugins: ['@tailwindcss/typography']
}
});Validates CSS variables for registry item.
const registryItemCssVarsSchema: z.ZodObject<{
theme?: Record<string, string>
light?: Record<string, string>
dark?: Record<string, string>
}>Usage Example:
import { registryItemCssVarsSchema } from 'shadcn/schema';
const cssVars = registryItemCssVarsSchema.parse({
light: {
'background': '0 0% 100%',
'foreground': '222.2 84% 4.9%'
},
dark: {
'background': '222.2 84% 4.9%',
'foreground': '210 40% 98%'
}
});Validates CSS definitions for registry item. Supports recursive CSS property structures.
const registryItemCssSchema: z.ZodRecord<string, any>Usage Example:
import { registryItemCssSchema } from 'shadcn/schema';
const css = registryItemCssSchema.parse({
'@layer base': {
':root': {
'--background': '0 0% 100%',
'--foreground': '222.2 84% 4.9%'
}
}
});Validates environment variables for registry item.
const registryItemEnvVarsSchema: z.ZodRecord<string, string>Usage Example:
import { registryItemEnvVarsSchema } from 'shadcn/schema';
const envVars = registryItemEnvVarsSchema.parse({
'NEXT_PUBLIC_API_URL': 'https://api.example.com',
'API_SECRET_KEY': 'secret_key_here'
});Validates font metadata for registry:font items.
const registryItemFontSchema: z.ZodObject<{
family: string
provider: "google"
import: string
variable: string
weight?: string[]
subsets?: string[]
}>Usage Example:
import { registryItemFontSchema } from 'shadcn/schema';
const font = registryItemFontSchema.parse({
family: 'Inter',
provider: 'google',
import: 'Inter',
variable: '--font-inter',
weight: ['400', '500', '600', '700'],
subsets: ['latin']
});Common fields shared by all registry items.
const registryItemCommonSchema: z.ZodObject<{
$schema?: string
extends?: string
name: string
title?: string
author?: string // Min 2 characters
description?: string
dependencies?: string[]
devDependencies?: string[]
registryDependencies?: string[]
files?: RegistryItemFile[]
tailwind?: RegistryItemTailwind
cssVars?: RegistryItemCssVars
css?: RegistryItemCss
envVars?: Record<string, string>
meta?: Record<string, any>
docs?: string
categories?: string[]
}>Complete registry item schema. Discriminated union by type for type-specific fields.
const registryItemSchema: z.ZodDiscriminatedUnion<"type", [
// registry:base has config field
z.ZodObject<{
type: "registry:base"
config?: Partial<RawConfig>
// ...all common fields
}>,
// registry:font has font field
z.ZodObject<{
type: "registry:font"
font: RegistryItemFont
// ...all common fields
}>,
// Other types
z.ZodObject<{
type: RegistryItemType // Excluding base and font
// ...all common fields
}>
]>Usage Example:
import { registryItemSchema, type RegistryItem } from 'shadcn/schema';
// UI component
const button: RegistryItem = registryItemSchema.parse({
name: 'button',
type: 'registry:ui',
description: 'A button component',
dependencies: ['class-variance-authority'],
registryDependencies: ['utils'],
files: [
{
path: 'components/ui/button.tsx',
type: 'registry:ui',
content: '/* component code */'
}
]
});
// Base item with config
const base = registryItemSchema.parse({
name: 'base',
type: 'registry:base',
config: {
tailwind: {
cssVariables: true
}
}
});
// Font item
const fontItem = registryItemSchema.parse({
name: 'inter',
type: 'registry:font',
font: {
family: 'Inter',
provider: 'google',
import: 'Inter',
variable: '--font-inter'
}
});Validates complete registry with metadata and items.
const registrySchema: z.ZodObject<{
name: string
homepage: string
items: RegistryItem[]
}>Usage Example:
import { registrySchema, type Registry } from 'shadcn/schema';
const registry: Registry = registrySchema.parse({
name: 'shadcn',
homepage: 'https://ui.shadcn.com',
items: [
{
name: 'button',
type: 'registry:ui',
/* ... */
},
{
name: 'card',
type: 'registry:ui',
/* ... */
}
]
});Validates registry index (array of registry items).
const registryIndexSchema: z.ZodArray<typeof registryItemSchema>Usage Example:
import { registryIndexSchema } from 'shadcn/schema';
const index = registryIndexSchema.parse([
{
name: 'button',
type: 'registry:ui',
description: 'A button component',
registryDependencies: ['utils']
},
{
name: 'card',
type: 'registry:ui',
description: 'A card component'
}
]);Validates available styles from registry.
const stylesSchema: z.ZodArray<
z.ZodObject<{
name: string
label: string
description?: string
}>
>Validates icon libraries configuration. Maps icon library names to their configuration objects (as string-to-string records).
const iconsSchema: z.ZodRecord<
z.ZodString, // Icon library name
z.ZodRecord<z.ZodString, z.ZodString> // Configuration as key-value pairs
>Structure: Record<string, Record<string, string>> - Nested record where each icon library is mapped to its configuration properties as key-value string pairs.
Validates base color configuration with inline colors and CSS variables.
const registryBaseColorSchema: z.ZodObject<{
inlineColors: z.ZodObject<{
light: z.ZodRecord<z.ZodString, z.ZodString>
dark: z.ZodRecord<z.ZodString, z.ZodString>
}>
cssVars: RegistryItemCssVars
cssVarsV4?: RegistryItemCssVars // Optional
inlineColorsTemplate: z.ZodString
cssVarsTemplate: z.ZodString
}>Fields:
inlineColors - Inline color definitions for light and dark themescssVars - CSS variable definitions using RegistryItemCssVars schemacssVarsV4 - Optional CSS variables for v4 compatibilityinlineColorsTemplate - Template string for inline colorscssVarsTemplate - Template string for CSS variablesValidates resolved items tree with dependencies and all component metadata. Includes all fields from registryItemCommonSchema that are needed for installation.
const registryResolvedItemsTreeSchema: z.ZodObject<{
dependencies?: string[]
devDependencies?: string[]
files?: RegistryItemFile[]
tailwind?: RegistryItemTailwind
cssVars?: RegistryItemCssVars
css?: RegistryItemCss
envVars?: Record<string, string>
docs?: string
fonts?: Array<RegistryFontItem> // Optional, for font items
}>Fields:
dependencies - npm package dependenciesdevDependencies - npm dev dependenciesfiles - Component files to installtailwind - Tailwind configuration updatescssVars - CSS variable definitionscss - CSS content to addenvVars - Environment variables requireddocs - Documentation URL or contentfonts - Font items (optional, for components that include fonts)Validates single search result item.
const searchResultItemSchema: z.ZodObject<{
name: string
type?: string
description?: string
registry: string
addCommandArgument: string
}>Validates search results with pagination metadata.
const searchResultsSchema: z.ZodObject<{
pagination: {
total: number
offset: number
limit: number
hasMore: boolean
}
items: SearchResultItem[]
}>Validates registries index listing available registries. Maps registry namespace names to their URLs.
const registriesIndexSchema: z.ZodRecord<
z.ZodString, // Namespace (must match /^@[a-zA-Z0-9][a-zA-Z0-9-_]*$/)
z.ZodString // Registry URL
>Structure: Record<string, string> - Maps registry namespace (e.g., @shadcn) to registry URL. The namespace key must start with @ and contain only alphanumeric characters, hyphens, and underscores.
Validates preset configuration for project initialization. Contains all settings for a complete shadcn/ui preset.
const presetSchema: z.ZodObject<{
name: string
title: string
description: string
base: string
style: string
baseColor: string
theme: string
iconLibrary: string
font: string
menuAccent: "subtle" | "bold"
menuColor: "default" | "inverted"
radius: string
}>Fields:
name - Preset identifier (e.g., "default", "new-york")title - Display title for the presetdescription - Preset descriptionbase - Base configuration presetstyle - UI style (e.g., "default", "new-york")baseColor - Base color palette (e.g., "slate", "zinc")theme - Theme nameiconLibrary - Icon library to use (e.g., "lucide", "phosphor")font - Font configurationmenuAccent - Menu accent stylemenuColor - Menu color schemeradius - Border radius valueValidates config.json from registry containing presets.
const configJsonSchema: z.ZodObject<{
presets: Preset[]
}>All schemas have corresponding TypeScript types inferred via z.infer<>:
// Infer types from schemas
type RegistryItem = z.infer<typeof registryItemSchema>
type RegistryBaseItem = Extract<RegistryItem, { type: "registry:base" }>
type RegistryFontItem = Extract<RegistryItem, { type: "registry:font" }>
type Registry = z.infer<typeof registrySchema>
type RegistryIndex = z.infer<typeof registryIndexSchema>
type RegistryResolvedItemsTree = z.infer<typeof registryResolvedItemsTreeSchema>
type Config = z.infer<typeof configSchema>
type RawConfig = z.infer<typeof rawConfigSchema>
type RegistryConfig = z.infer<typeof registryConfigSchema>
type SearchResults = z.infer<typeof searchResultsSchema>
type SearchResultItem = z.infer<typeof searchResultItemSchema>
type RegistriesIndex = z.infer<typeof registriesIndexSchema>
type RegistryBaseColor = z.infer<typeof registryBaseColorSchema>
type Style = z.infer<typeof stylesSchema>[number]
type Icons = z.infer<typeof iconsSchema>
type Preset = z.infer<typeof presetSchema>
type ConfigJson = z.infer<typeof configJsonSchema>
// Registry item sub-types
type RegistryItemFile = z.infer<typeof registryItemFileSchema>
type RegistryItemTailwind = z.infer<typeof registryItemTailwindSchema>
type RegistryItemCssVars = z.infer<typeof registryItemCssVarsSchema>
type RegistryItemCss = z.infer<typeof registryItemCssSchema>
type RegistryItemEnvVars = z.infer<typeof registryItemEnvVarsSchema>
type RegistryItemFont = z.infer<typeof registryItemFontSchema>
type RegistryItemType = z.infer<typeof registryItemTypeSchema>
// Import types directly
import type {
RegistryItem,
RegistryBaseItem,
RegistryFontItem,
Registry,
RegistryIndex,
RegistryResolvedItemsTree,
Config,
RawConfig,
RegistryConfig,
SearchResults,
SearchResultItem,
RegistriesIndex,
RegistryBaseColor,
Preset,
ConfigJson,
RegistryItemFile,
RegistryItemTailwind,
RegistryItemCssVars,
RegistryItemCss,
RegistryItemEnvVars,
RegistryItemFont,
RegistryItemType
} from 'shadcn/schema';import { configSchema } from 'shadcn/schema';
try {
const config = configSchema.parse(userInput);
// Config is valid and typed
} catch (error) {
if (error instanceof z.ZodError) {
console.error('Validation errors:', error.errors);
// error.errors is an array of ZodIssue objects
// Each issue has: path, message, code, etc.
}
}import { registryItemSchema } from 'shadcn/schema';
const result = registryItemSchema.safeParse(data);
if (result.success) {
// result.data is typed RegistryItem
console.log(result.data.name);
} else {
// result.error contains validation errors
console.error(result.error.errors);
// result.error is a ZodError with detailed validation issues
}import { type RegistryItem } from 'shadcn/schema';
function isFontItem(item: RegistryItem): item is RegistryFontItem {
return item.type === 'registry:font';
}
function isBaseItem(item: RegistryItem): item is RegistryBaseItem {
return item.type === 'registry:base';
}
// Usage
if (isFontItem(item)) {
console.log(item.font.family); // TypeScript knows font exists
}import { registryItemSchema } from 'shadcn/schema';
// Validate only specific fields
const partialSchema = registryItemSchema.pick({ name: true, type: true });
const result = partialSchema.parse({ name: 'button', type: 'registry:ui' });import { z } from 'zod';
import { registryItemSchema } from 'shadcn/schema';
// Add custom validation
const customSchema = registryItemSchema.refine(
(item) => item.files && item.files.length > 0,
{
message: "Item must have at least one file"
}
);Zod validation errors provide detailed information:
import { configSchema } from 'shadcn/schema';
import { z } from 'zod';
try {
const config = configSchema.parse(invalidConfig);
} catch (error) {
if (error instanceof z.ZodError) {
error.errors.forEach((issue) => {
console.error(`Path: ${issue.path.join('.')}`);
console.error(`Message: ${issue.message}`);
console.error(`Code: ${issue.code}`);
});
}
}Common Zod Error Codes:
invalid_type - Type mismatchinvalid_string - String validation failedtoo_small - Value too small (min length, etc.)too_big - Value too large (max length, etc.)invalid_enum_value - Value not in enumcustom - Custom validation errorimport { registryItemSchema } from 'shadcn/schema';
import { getRegistryItems } from 'shadcn';
async function safeGetRegistryItems(items: string[]) {
const rawItems = await getRegistryItems(items);
// Validate each item
return rawItems.map(item => {
const result = registryItemSchema.safeParse(item);
if (!result.success) {
throw new Error(`Invalid registry item: ${result.error.message}`);
}
return result.data;
});
}import { rawConfigSchema, configSchema } from 'shadcn/schema';
import { readFile } from 'fs/promises';
import { resolve } from 'path';
async function loadAndValidateConfig(cwd: string) {
const configPath = resolve(cwd, 'components.json');
const raw = await readFile(configPath, 'utf-8');
const json = JSON.parse(raw);
// Validate raw config
const rawConfig = rawConfigSchema.parse(json);
// Resolve paths and validate full config
// (path resolution logic here)
const config = configSchema.parse({
...rawConfig,
resolvedPaths: { /* ... */ }
});
return config;
}