Skip to content

Packages

Most functionality lives in laikacms as subpath exports; specialized integrations live in their own packages.

Repository layout (June 2026, updated July 2026). This monorepo now carries only the two core packages — laikacms and @laikacms/decap (@laikacms/decap-ai and the client-side decap extras moved into the @laikacms/decap-cms fork in July 2026, DCMS-492). The other packages documented below (@laikacms/aws, @laikacms/github, @laikacms/git-gateway, laikacli, decap-cms-widget-lexicaleditor, decap-cms-widget-portabletext-editor, decap-cms-lexical-core, and the rest of the adapters) are still published to npm under the same names but are now developed in separate repositories. See the restructure note for details and the current status of the moved repos.

laikacms

The core package: domain types, API factories, default implementations, serializers, and shared utilities. Imported via subpath exports.

Domain (packages/laikacms/src/domain/)

SubpathDescription
laikacms/storageStorage abstractions (objects, folders, atoms)
laikacms/documentsDocument management with revisions
laikacms/assetsAsset/media management
laikacms/contentbase-settingsContentBase configuration

API (packages/laikacms/src/api/)

SubpathDescription
laikacms/storage/apiJSON:API for storage
laikacms/documents/apiJSON:API for documents
laikacms/assets/apiJSON:API for assets
laikacms/contentbase-apiJSON:API for ContentBase

Implementations (packages/laikacms/src/impl/)

SubpathDescription
laikacms/storage/r2Cloudflare R2 storage
laikacms/storage/fsFilesystem storage
laikacms/storage/s3S3→R2Bucket adapter (createS3Bucket()) — pairs with R2StorageRepository, not a StorageRepository itself. See @laikacms/aws/storage-s3 for the full S3 StorageRepository.
laikacms/storage/webdavWebDAV server
laikacms/storage/drizzleDrizzle ORM storage
laikacms/storage/jsonapi-proxyStorage JSON:API proxy
laikacms/assets/r2R2 asset storage
laikacms/assets/contentbaseAssets on top of storage
laikacms/assets/obsidianObsidian-vault-backed assets
laikacms/assets/jsonapi-proxyAssets JSON:API proxy
laikacms/documents/contentbaseDocuments on top of storage
laikacms/documents/drizzleDrizzle document storage
laikacms/documents/obsidianObsidian-vault-backed documents
laikacms/documents/jsonapi-proxyDocuments JSON:API proxy
laikacms/contentbase-settings-defaultDefault settings impl
laikacms/contentbase-settings-decapDecap-CMS-compatible settings

Testing utilities (packages/laikacms/src/)

SubpathDescription
laikacms/documents/testingContract test harness for DocumentsRepository implementations
laikacms/storage/testingContract test harness for StorageRepository implementations
laikacms/assets/testingContract test harness for AssetsRepository implementations

Serializers (packages/laikacms/src/serializers/)

SubpathDescription
laikacms/serializers/jsonJSON serialization
laikacms/serializers/yamlYAML serialization
laikacms/serializers/markdownMarkdown with frontmatter
laikacms/serializers/rawRaw binary/text

Shared (packages/laikacms/src/shared/)

SubpathDescription
laikacms/compatPromise-bridge helpers (runTask, collectStream) for consuming LaikaTask/LaikaStream without importing effect directly
laikacms/coreTypes, errors, utilities
laikacms/core/errorsDomain error classes (LaikaError subclasses: NotFoundError, BadRequestError, InternalError, etc.)
laikacms/core/errors-extraHTTP adapter utilities: ErrorCodeToStatusMap (error code → HTTP status), ErrorCodeToKeyMap, ErrorClasses
laikacms/core/types/*Targeted type modules — datetime, effect, ext-name, mime-type, pagination, role, role-permission
laikacms/cryptoCryptographic utilities
laikacms/file-sanitizerFile upload sanitization
laikacms/i18nInternationalization (bundle index)
laikacms/i18n/enEnglish translations
laikacms/i18n/nlDutch translations
laikacms/json-apiJSON:API utilities
laikacms/sanitizerInput sanitization

@laikacms/aws

AWS service implementations.

SubpathDescription
@laikacms/aws/contentbase-settings-ddbDynamoDB-backed contentbase settings
@laikacms/aws/storage-s3S3-backed StorageRepository (also works with MinIO, Backblaze B2, DigitalOcean Spaces)
@laikacms/aws/storage-ddbDynamoDB single-table StorageRepository
@laikacms/aws/assets-s3S3-backed AssetsRepository

@laikacms/decap

Decap CMS server-side integrations: the Decap-compatible API and the OAuth2 server.

Moved (July 2026, DCMS-492): AI chat (@laikacms/decap-ai, now discontinued), the icon widgets, the Dutch locale, the embedded-entry editor component, and the config type utilities all moved into the @laikacms/decap-cms fork: @laikacms/decap-cms/ai, …/widgets/aichat, …/widgets/lucide-icon, …/widgets/radix-icon, …/locales/nl, …/editor-component-embedded-entry, and …/config-types.

SubpathDescription
@laikacms/decap-cms/backends/laikaDecap CMS backend (lives in the fork)
@laikacms/decap/decap-apiDecap-compatible API
@laikacms/decap/decap-oauth2OAuth2 server with PKCE
@laikacms/decap/decap-oauth2/i18ni18n bundle index for the OAuth2 UI
@laikacms/decap/decap-oauth2/i18n/enEnglish translations for the OAuth2 UI
@laikacms/decap/decap-oauth2/i18n/nlDutch translations for the OAuth2 UI

decap-cms-lexical-core

Developed in a separate repository (moved out June 2026). Still published to npm under the same name. See the restructure note.

Lexical-specific bindings for the editor-agnostic @laikacloud/portabletext-core: Portable Text ↔ Lexical bridge, headless editor factory, custom blocks subsystem, and the LexicalRichtextValue class that derives canonical Portable Text from a Lexical editor state on every change.

Install

bash
pnpm add decap-cms-lexical-core

Main exports

ExportDescription
LexicalRichtextValueRichtextValue subclass that owns a Lexical EditorState and produces Portable Text
createHeadlessEditor()Creates a Lexical headless editor with the standard node set pre-registered
defaultNodesArray of Lexical EditorNode constructors used by the standard headless editor
lexicalToPortableText()Convert a Lexical EditorState to a PortableTextDocument
portableTextToLexical()Populate a Lexical editor from a PortableTextDocument
emptyPortableText()Returns a minimal valid empty PortableTextDocument
BlockNode / blocksContextCustom block subsystem for embedding arbitrary Decap entries inside Lexical
Everything from @laikacloud/portabletext-coreRe-exported for convenience (Mapper, RichtextValue, createKeyGenerator, …)

decap-cms-widget-lexicaleditor

Developed in a separate repository (moved out June 2026). Still published to npm under the same name. See the restructure note.

Lexical-based rich text widget for Decap CMS, built on a shadcn-editor fork. Stores content as Portable Text (via decap-cms-lexical-core) and renders a full-featured editor toolbar in the Decap CMS control panel.

Install

bash
pnpm add decap-cms-widget-lexicaleditor decap-cms-lexical-core

Main exports

ExportDescription
WidgetDecap CMS widget definition object — pass to CMS.registerWidget()
LexicalControlReact control component (rendered in the Decap CMS editor panel)
LexicalPreviewReact preview component (rendered in the Decap CMS preview panel)
lexicalEditorWidgetSchemaZod schema for the widget field configuration
passthroughSerializerSerializer that stores the Portable Text value as-is (no conversion)
EditorThe standalone Lexical editor React component (usable outside Decap)

Basic usage

ts
import CMS from 'decap-cms-app';
import { Widget } from 'decap-cms-widget-lexicaleditor';

CMS.registerWidget(Widget);

Then in your Decap CMS config:

yaml
collections:
  - name: posts
    fields:
      - name: body
        widget: lexicaleditor

decap-cms-widget-portabletext-editor

Developed in a separate repository (moved out June 2026). Still published to npm under the same name. See the restructure note.

Decap CMS widget backed by @portabletext/editor (Sanity's native Portable Text editor). A sibling of decap-cms-widget-lexicaleditor — choose this one when you want the official Portable Text editing experience instead of Lexical.

Install

bash
pnpm add decap-cms-widget-portabletext-editor

Main exports

ExportDescription
WidgetDecap CMS widget definition object — pass to CMS.registerWidget()
PortableTextEditorControlReact control component (rendered in the Decap CMS editor panel)
PortableTextEditorPreviewReact preview component (rendered in the Decap CMS preview panel)
PortableTextEditorViewThe standalone Portable Text editor React component (usable outside Decap)
schemaDefault @portabletext/editor schema used by the widget

Basic usage

ts
import CMS from 'decap-cms-app';
import { Widget } from 'decap-cms-widget-portabletext-editor';

CMS.registerWidget(Widget);

Then in your Decap CMS config:

yaml
collections:
  - name: posts
    fields:
      - name: body
        widget: portabletext-editor

@laikacms/github

GitHub-backed StorageRepository (GitHub App authentication).

SubpathDescription
@laikacms/github/storage-ghGitHub-backed storage repository

GithubDataSourceOptions

GithubStorageRepository accepts a GithubDataSourceOptions object. Notable option:

OptionTypeDescription
octokitOctokit (optional)Pre-configured Octokit instance. When provided, overrides the built-in GitHub App auth — useful for testing or fine-grained token auth.

@laikacms/git-gateway

Drop-in Netlify git-gateway-compatible HTTP handler. Lets Decap CMS (configured with backend: { name: git-gateway }) talk to a fixed GitHub repo through a GitHub App installation token, behind a pluggable Bearer-token verifier. Runtime-agnostic — runs on Cloudflare Workers, Node, Bun, Deno, or anywhere Hono is supported.

SubpathDescription
.gitGateway() Hono app factory (root export)

gitGateway(options) options

OptionTypeDescription
verifyToken(token: string) => Promise<User | null>Validates the incoming Bearer token. Return null (or throw) to reject.
github{ appId, privateKey, installationId, owner, repo, apiBase? }GitHub App credentials. apiBase defaults to https://api.github.com (useful for GHE).
allowedRolesstring[] (optional)When set, the user returned by verifyToken must have at least one matching role.
logger{ error, warn, info?, debug? } (optional)Pluggable structured logger (pino, bunyan, etc.). Only error and warn are required; info and debug are optional. Defaults to a no-op.
userAgentstring (optional)Custom User-Agent for outgoing GitHub API requests. Defaults to @laikacms/git-gateway.

Endpoints

MethodPathAuthDescription
GET/healthReturns { ok: true }. Cheap load-balancer health check.
GET/settingsReturns { version, github_enabled, roles, user }.
ALL/github/*Proxies to https://api.github.com/repos/{owner}/{repo}/* via an installation token.

The /github/* proxy allows only the same subset of endpoints as Netlify's gateway: git/*, contents/*, pulls/*, branches/*, merges/*, statuses/*, compare/*, commits/*, and issues/:n/labels. All other paths return 403 FORBIDDEN.

Usage

Mount it inside an existing Hono app:

ts
import { gitGateway } from '@laikacms/git-gateway';
import { Hono } from 'hono';

const app = new Hono<{ Bindings: Env }>();

app.route(
  '/.netlify/git',
  gitGateway({
    verifyToken: async token => {
      const r = await fetch('https://api.github.com/user', {
        headers: { Authorization: `token ${token}`, 'User-Agent': 'gg' },
      });
      if (!r.ok) return null;
      const u = await r.json();
      return { id: String(u.id), email: u.email, name: u.name };
    },
    github: {
      appId: env.GITHUB_APP_ID,
      privateKey: env.GITHUB_APP_PRIVATE_KEY,
      installationId: env.GITHUB_APP_INSTALLATION_ID,
      owner: 'acme',
      repo: 'website',
    },
  }),
);

Then in your Decap CMS config:

yaml
backend:
  name: git-gateway
  gateway_url: https://your-worker.dev/.netlify/git

laikacli

The Laika CMS command-line interface for local development workflows. Provides a short laika bin alias once installed; the canonical package name is laikacli (the laika npm name is taken by an unrelated package).

Supersedes the deprecated @laikacms/local package.

Install

sh
pnpm add -D laikacli

Or run without installing:

sh
npx laikacli local serve
pnpm dlx laikacli local serve

Commands

All local-file dev tooling lives under the local namespace.

CommandWhat it does
local serveStart a local-file JSON:API storage server for dev workflows (--root, --port, --host, --default-extension (default: md), --auth-token)
local generateGenerate a typed TypeScript module from a Decap CMS config.yaml (add --watch to keep it fresh)
local migrateCopy every atom from one storage repository to another (-s ./source -d ./dest)

Run laika local <command> --help for the full flag reference.

Programmatic API

All CLI commands are also exported from the package root for embedding in your own scripts or Effect CLI applications:

ts
import { generateConfig, layerStorageServer, runMigrate } from 'laikacli';

Released under the MIT License.