;
}
```
--------------------------------
### Exported members from @keystatic/core
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/STRUCTURE.md
Core configuration and field definitions available from the main package.
```typescript
config, collection, singleton
Fields: text, slug, integer, number, date, datetime, checkbox, select, multiselect, url, image, file, document, array, object, conditional, relationship, multiRelationship, blocks
```
--------------------------------
### Define cloud storage configuration
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/configuration.md
Defines the structure and usage for Keystatic Cloud storage.
```typescript
storage: {
kind: 'cloud';
pathPrefix?: string;
branchPrefix?: string;
}
cloud: {
project: string;
}
```
```typescript
export default config({
storage: {
kind: 'cloud',
pathPrefix: 'content',
},
cloud: {
project: 'your-project-id',
},
collections: { /* ... */ },
});
```
--------------------------------
### Configure Keystatic for Next.js
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/configuration.md
Defines the storage provider and content collections for a Keystatic project. This configuration is compatible with Next.js, Remix, and Astro.
```typescript
// keystatic.config.ts
import { config, collection, singleton, fields } from '@keystatic/core';
export default config({
storage: {
kind: 'github',
repo: { owner: 'acme', name: 'website' },
},
collections: {
posts: collection({
label: 'Blog Posts',
slugField: 'slug',
schema: {
title: fields.text({ label: 'Title' }),
slug: fields.slug({ label: 'Slug' }),
content: fields.document({ label: 'Content' }),
},
}),
},
});
```
--------------------------------
### Usage: Read Entry or Throw
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/reader.md
Retrieve an entry and handle potential missing entries via try-catch.
```typescript
try {
const post = await reader.collections.posts.readOrThrow('my-post');
console.log(post.title);
} catch (error) {
console.error('Post not found:', error);
}
```
--------------------------------
### Define Locale Configuration
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/configuration.md
Sets the default language for the Keystatic admin interface.
```typescript
locale?: Locale
```
```typescript
export default config({
locale: 'es',
storage: { kind: 'local' },
collections: { /* ... */ },
});
```
--------------------------------
### Integrate with Remix
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/api-handler.md
Implementation of the Keystatic API handler within a Remix route file using loader and action functions.
```typescript
// routes/api/keystatic/$.tsx
import { json, type LoaderFunction } from '@remix-run/node';
import { makeGenericAPIRouteHandler } from '@keystatic/core/api/generic';
import config from '@/keystatic.config';
const handler = makeGenericAPIRouteHandler({
config,
clientId: process.env.KEYSTATIC_GITHUB_CLIENT_ID,
clientSecret: process.env.KEYSTATIC_GITHUB_CLIENT_SECRET,
secret: process.env.KEYSTATIC_SECRET,
});
export const loader: LoaderFunction = async ({ request }) => {
const keystatic = await handler({
method: request.method,
headers: Object.fromEntries(request.headers),
url: request.url,
body: await request.text(),
});
return new Response(keystatic.body, {
status: keystatic.status,
headers: keystatic.headers,
});
};
export const action = loader;
```
--------------------------------
### Define Keystatic Configuration
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/configuration.md
A complete configuration object defining storage, UI, collections, and singletons for a Keystatic project.
```typescript
import { config, collection, singleton, fields } from '@keystatic/core';
export default config({
// Storage configuration
storage: {
kind: 'github',
repo: { owner: 'acme', name: 'website' },
pathPrefix: 'content',
branchPrefix: 'edit-',
},
// Localization
locale: 'en',
// UI Customization
ui: {
brand: {
name: 'Acme CMS',
mark: ({ colorScheme }) => (
{colorScheme === 'light' ? '🏢' : '🌙'}
),
},
navigation: {
'Content': ['posts', 'pages'],
'Taxonomies': ['categories', 'tags'],
'Settings': ['siteConfig', 'navigation'],
},
},
// Collections
collections: {
posts: collection({
label: 'Blog Posts',
path: 'blog/posts/**',
format: { data: 'yaml', contentField: 'content' },
entryLayout: 'content',
slugField: 'slug',
previewUrl: 'https://acme.com/blog/{slug}',
columns: ['title', 'date', 'status'],
schema: {
title: fields.text({
label: 'Title',
validation: { isRequired: true },
}),
slug: fields.slug({ label: 'URL Slug' }),
date: fields.date({
label: 'Published Date',
defaultValue: { kind: 'today' },
}),
status: fields.select({
label: 'Status',
options: [
{ label: 'Draft', value: 'draft' },
{ label: 'Published', value: 'published' },
],
defaultValue: 'draft',
}),
author: fields.relationship({
label: 'Author',
collection: 'authors',
validation: { isRequired: true },
}),
tags: fields.multiRelationship({
label: 'Tags',
collection: 'tags',
}),
content: fields.document({
label: 'Content',
formatting: {
headingLevels: [1, 2, 3],
inlineMarks: ['bold', 'italic', 'code'],
},
dividers: true,
images: { directory: 'blog-images' },
}),
},
}),
pages: collection({
label: 'Pages',
path: 'pages/*',
format: 'json',
entryLayout: 'form',
slugField: 'slug',
schema: {
title: fields.text({ label: 'Title' }),
slug: fields.slug({ label: 'Slug' }),
content: fields.document({ label: 'Content' }),
},
}),
authors: collection({
label: 'Authors',
path: 'authors/*',
format: 'json',
entryLayout: 'form',
slugField: 'slug',
schema: {
name: fields.text({ label: 'Name' }),
slug: fields.slug({ label: 'Slug' }),
email: fields.text({ label: 'Email' }),
bio: fields.text({ label: 'Bio', multiline: true }),
avatar: fields.image({ label: 'Avatar' }),
},
}),
tags: collection({
label: 'Tags',
path: 'tags/*',
format: 'json',
entryLayout: 'form',
slugField: 'slug',
schema: {
name: fields.text({ label: 'Name' }),
slug: fields.slug({ label: 'Slug' }),
description: fields.text({ label: 'Description' }),
},
}),
},
// Singletons
singletons: {
siteConfig: singleton({
label: 'Site Configuration',
path: 'config/site',
format: 'json',
schema: {
siteName: fields.text({ label: 'Site Name' }),
siteDescription: fields.text({ label: 'Description' }),
siteUrl: fields.url({ label: 'Site URL' }),
sitemapChangeFrequency: fields.select({
label: 'Sitemap Change Frequency',
options: [
{ label: 'Daily', value: 'daily' },
{ label: 'Weekly', value: 'weekly' },
{ label: 'Monthly', value: 'monthly' },
],
}),
},
}),
navigation: singleton({
label: 'Navigation',
path: 'config/navigation',
format: 'json',
schema: {
items: fields.array(
fields.object({
fields: {
label: fields.text({ label: 'Label' }),
url: fields.url({ label: 'URL' }),
children: fields.array(
fields.object({
fields: {
label: fields.text({ label: 'Label' }),
url: fields.url({ label: 'URL' }),
},
}),
{ label: 'Submenu Items' }
),
},
}),
{ label: 'Navigation Items' }
),
},
}),
},
});
```
--------------------------------
### Initialize and Access Reader
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/reader.md
Create a reader instance and access collections or singletons with type safety.
```typescript
const reader = createReader(process.cwd(), config);
// Type-safe collection access
const postReader: CollectionReader = reader.collections.posts;
// Type-safe singleton access
const settingsReader: SingletonReader = reader.singletons.settings;
```
--------------------------------
### Configure Admin Brand
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/configuration.md
Customizes the site name and logo component, supporting light and dark mode variants.
```typescript
ui: {
brand: {
name: 'Acme CMS',
mark: ({ colorScheme }) => (
),
},
}
```
--------------------------------
### Syntax Highlighting for Code Blocks
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/renderer.md
Integrate prism-react-renderer to provide syntax highlighting for code blocks.
```typescript
import { highlight } from 'prism-react-renderer';
const customRenderers: Renderers = {
inline: defaultRenderers.inline,
block: {
...defaultRenderers.block,
code: ({ children, language = 'plaintext' }) => {
const tokens = highlight(children, language);
return (
{tokens.map((token, i) => (
{token.content}
))}
);
},
},
};
```
--------------------------------
### Lazy-load Keystatic Admin with Next.js dynamic
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/ui-exports.md
Use dynamic imports to lazy-load the Admin component and disable SSR to prevent hydration issues.
```typescript
// pages/admin/[[...params]].tsx
import dynamic from 'next/dynamic';
import config from '@/keystatic.config';
const Admin = dynamic(
() => import('@keystatic/core/ui').then(mod => mod.Admin),
{ ssr: false }
);
export default function AdminPage() {
return ;
}
```
--------------------------------
### readOrThrow()
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/reader.md
Reads a singleton entry. Returns the entry object if found, or throws an error if it does not exist.
```APIDOC
## readOrThrow(opts?: EntryReaderOpts)
### Description
Read the singleton entry. Throws an error if the entry does not exist.
### Parameters
- **opts.resolveLinkedFiles** (boolean) - Optional - Resolve nested linked file content.
### Example
```typescript
const settings = await reader.singletons.settings.readOrThrow();
```
```
--------------------------------
### Define local storage configuration
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/configuration.md
Defines the structure and usage for local file system storage, intended for development and testing.
```typescript
storage: {
kind: 'local';
}
```
```typescript
export default config({
storage: { kind: 'local' },
collections: { /* ... */ },
});
```
--------------------------------
### object(options)
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/form-fields.md
Creates a composite field containing multiple named fields.
```APIDOC
## object(options)
### Description
Composite field containing multiple named fields.
### Parameters
- **label** (string) - Optional - Field group label
- **fields** (Record) - Required - Named field definitions
- **layout** ('form' | 'block') - Optional - UI layout
### Example
```typescript
const author = fields.object({
label: 'Author',
fields: {
name: fields.text({ label: 'Name' }),
email: fields.text({ label: 'Email' }),
bio: fields.text({ label: 'Bio', multiline: true }),
},
});
```
```
--------------------------------
### Render Keystatic Documents
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/README.md
Use DocumentRenderer to display content, optionally overriding default renderers for custom styling.
```typescript
import { defaultRenderers } from '@keystatic/core/renderer';
export function BlogPost({ content }) {
return (
);
}
// Or customize renderers:
const customRenderers = {
...defaultRenderers,
block: {
...defaultRenderers.block,
heading: ({ level, children }) => (
{children}
),
},
};
```
--------------------------------
### Development Mode Missing Configuration Error
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/api-handler.md
The error message displayed in development mode when required configuration is missing.
```text
Missing required config in Keystatic API setup when using the 'github' storage mode:
- clientId (can be provided via KEYSTATIC_GITHUB_CLIENT_ID env var)
- clientSecret (can be provided via KEYSTATIC_GITHUB_CLIENT_SECRET env var)
- secret (can be provided via KEYSTATIC_SECRET env var)
```
--------------------------------
### Mount Keystatic Admin in Next.js Pages Router
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/ui-exports.md
Standard implementation for the Pages Router directory structure.
```typescript
// pages/admin/[[...params]].tsx
import { Admin } from '@keystatic/core/ui';
import config from '@/keystatic.config';
export default function KeystaticAdminPage() {
return ;
}
```
--------------------------------
### Configure Collection Path
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/configuration.md
Defines the file system path pattern for entries using glob syntax.
```typescript
path?: `${string}/${Glob}` | `${string}/${Glob}/${string}`
```
```typescript
// Flat: content/posts/{slug}.md
path: 'content/posts/*'
// Nested: content/blog/2024/06/{slug}.md
path: 'content/blog/**'
// Custom subdirectories: content/posts/{slug}/index.md
path: 'content/posts/{slug}'
// Template: content/*/articles/*'
path: 'content/*/articles/*'
```
--------------------------------
### Integrate Keystatic with Next.js App Router
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/README.md
Configure the admin page and API route handler for Next.js applications.
```typescript
// app/admin/[[...params]]/page.tsx
'use client';
import { Admin } from '@keystatic/core/ui';
import config from '@/keystatic.config';
export default function AdminPage() {
return ;
}
```
```typescript
// app/api/keystatic/[...params]/route.ts
import { makeGenericAPIRouteHandler } from '@keystatic/core/api/generic';
import config from '@/keystatic.config';
const handler = makeGenericAPIRouteHandler({
config,
clientId: process.env.KEYSTATIC_GITHUB_CLIENT_ID,
clientSecret: process.env.KEYSTATIC_GITHUB_CLIENT_SECRET,
secret: process.env.KEYSTATIC_SECRET,
});
export const GET = handler;
export const POST = handler;
```
--------------------------------
### Define a singleton
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/configuration.md
Creates a unique, singular content entry definition.
```typescript
import { singleton, fields } from '@keystatic/core';
const settings = singleton({
label: 'Site Settings',
path: 'config/settings',
format: 'json',
schema: {
siteName: fields.text({ label: 'Site Name' }),
siteDescription: fields.text({ label: 'Description' }),
socialLinks: fields.object({
fields: {
twitter: fields.url({ label: 'Twitter URL' }),
github: fields.url({ label: 'GitHub URL' }),
},
}),
},
});
```
--------------------------------
### Configure and Render Document Field
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/renderer.md
Defines the document field schema with specific formatting options and demonstrates rendering the content using DocumentRenderer.
```typescript
import { fields } from '@keystatic/core';
import { defaultRenderers } from '@keystatic/core/renderer';
// In schema:
const blogPost = collection({
// ...
schema: {
content: fields.document({
label: 'Content',
// Configure which block types are available
formatting: {
inlineMarks: ['bold', 'italic', 'code'],
headingLevels: [1, 2, 3],
},
dividers: true,
links: true,
images: true,
tables: true,
}),
},
});
// When rendering:
import { reader } from '@/lib/keystatic';
export async function getStaticProps() {
const post = await reader.collections.posts.read('my-post');
return { props: { post } };
}
export default function Page({ post }) {
return (
{post.title}
);
}
```
--------------------------------
### EntryLayout Type Definition
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/configuration.md
Defines the available editor UI layouts.
```typescript
type EntryLayout = 'content' | 'form'
```
--------------------------------
### Read Entry or Throw
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/reader.md
Signature for reading an entry that throws an error if not found.
```typescript
readOrThrow(slug: string, opts?: EntryReaderOpts): Promise
```
--------------------------------
### Define GitHub Storage in Config
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/README.md
Configuration object for enabling GitHub storage in your Keystatic config file.
```typescript
storage: {
kind: 'github',
repo: { owner: 'your-org', name: 'your-repo' },
}
```
--------------------------------
### Read All Entries
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/reader.md
Signature for retrieving all entries in a collection.
```typescript
all(opts?: EntryReaderOpts): Promise>
```
--------------------------------
### Integrate Keystatic with Astro
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/api-handler.md
Uses the generic API handler to manage Keystatic routes within an Astro API route file.
```typescript
// src/pages/api/keystatic/[...params].ts
import { makeGenericAPIRouteHandler } from '@keystatic/core/api/generic';
import type { APIRoute } from 'astro';
import config from '@/keystatic.config';
const handler = makeGenericAPIRouteHandler({
config,
clientId: import.meta.env.KEYSTATIC_GITHUB_CLIENT_ID,
clientSecret: import.meta.env.KEYSTATIC_GITHUB_CLIENT_SECRET,
secret: import.meta.env.KEYSTATIC_SECRET,
});
export const GET: APIRoute = async ({ request }) => {
const keystatic = await handler({
method: request.method,
headers: Object.fromEntries(request.headers),
url: request.url,
body: await request.text(),
});
return new Response(keystatic.body, {
status: keystatic.status,
headers: keystatic.headers,
});
};
export const POST = GET;
```
--------------------------------
### file
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/form-fields.md
Defines a single file asset field that returns a relative path.
```APIDOC
## file
### Description
Creates a single file asset field for file uploads.
### Signature
`fields.file(options: { label: string, description?: string, directory?: string, validation?: { isRequired?: boolean } }): AssetFormField`
### Parameters
- **label** (string) - Required - Field display name
- **description** (string) - Optional - Helper text
- **directory** (string) - Optional - Subdirectory for files (default: 'assets')
- **validation.isRequired** (boolean) - Optional - Whether file is required
### Returns
Relative path to file.
### Example
```typescript
const pdf = fields.file({
label: 'PDF Document',
directory: 'assets/documents',
});
```
```
--------------------------------
### fields.datetime
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/api-reference/form-fields.md
Creates a date and time picker field that returns an ISO 8601 string.
```APIDOC
## fields.datetime(options)
### Description
Creates a date and time picker field for selecting specific timestamps.
### Parameters
- **label** (string) - Required - Field display name
- **description** (string) - Optional - Helper text
- **defaultValue** (string | { kind: 'now' }) - Optional - Initial value or 'now'
- **validation.isRequired** (boolean) - Optional - Whether value is required
- **validation.min** (string) - Optional - Earliest allowed datetime
- **validation.max** (string) - Optional - Latest allowed datetime
### Example
```typescript
const createdAt = fields.datetime({
label: 'Created At',
defaultValue: { kind: 'now' },
validation: { isRequired: true },
});
```
```
--------------------------------
### Exported members from @keystatic/core/api/generic
Source: https://github.com/thinkmill/keystatic/blob/main/_autodocs/STRUCTURE.md
Generic API route handling utilities.
```typescript
makeGenericAPIRouteHandler, APIRouteConfig
```