No description
  • TypeScript 99.4%
  • Makefile 0.3%
  • JavaScript 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-07-23 14:44:50 +00:00
.claude chore: add openspec 2026-05-05 12:33:59 +02:00
.forgejo/workflows fix(ci): report every validation result 2026-07-23 11:49:48 +02:00
docs fix(apply): route stable ID changes through planning 2026-07-23 16:43:35 +02:00
openspec chore(workflow): migrate from OpenSpec to Wayfinder 2026-07-19 20:27:46 +02:00
src fix(apply): route stable ID changes through planning 2026-07-23 16:43:35 +02:00
test fix(apply): route stable ID changes through planning 2026-07-23 16:43:35 +02:00
.editorconfig chore: add tooling and build configuration 2026-05-07 14:34:31 +02:00
.gitignore chore: add tooling and build configuration 2026-05-07 14:34:31 +02:00
.node-version chore: pin local node version 2026-05-11 15:56:10 +02:00
.prettierignore fix(types-emit): preserve generated golden output 2026-07-23 12:08:11 +02:00
.prettierrc.mjs style: swap prettier config to .mjs and reformat 2026-05-11 15:55:53 +02:00
AGENTS.md chore(workflow): migrate from OpenSpec to Wayfinder 2026-07-19 20:27:46 +02:00
architecture-reference.md fix(apply): reject unsupported identifier renames 2026-07-22 18:23:19 +02:00
CONTEXT.md fix(apply): route stable ID changes through planning 2026-07-23 16:43:35 +02:00
eslint.config.js openspec: archive add-types-emit 2026-05-23 17:17:12 +02:00
Makefile feat(test): add real Directus integration harness 2026-07-21 21:50:06 +02:00
package-lock.json 0.1.1 2026-05-13 11:54:44 +02:00
package.json Merge branch 'main' into codex/remove-unsupported-renames 2026-07-23 10:39:33 +00:00
README.md fix(apply): reject unsupported identifier renames 2026-07-22 18:23:19 +02:00
tsconfig.json build: drop tsup, ship ESM-only via tsc 2026-05-11 15:56:17 +02:00
tsconfig.test.json feat(test): add real Directus integration harness 2026-07-21 21:50:06 +02:00
vitest.config.ts feat(test): add real Directus integration harness 2026-07-21 21:50:06 +02:00
vitest.integration.config.ts feat(test): add real Directus integration harness 2026-07-21 21:50:06 +02:00

Directus Development Kit (DDK)

A TypeScript DSL and apply engine for Directus schemas with programmatic authoring, stable identity, drift detection, and a safe plan/apply workflow.

Status: 0.x — under active development, breaking changes expected.

Quickstart

npm install @pienter-tech/directus-development-kit @directus/sdk
npx ddk init

ddk init writes a starter ddk.config.ts with a small worked example, which looks roughly like this:

// ddk.config.ts
import {
    Schema,
    Collection,
    StringField,
    UuidField,
    TimestampField,
    M2OField,
    EnvAuthProvider,
    directusUsers,
} from '@pienter-tech/directus-development-kit';

const articles = new Collection('articles', {
    id: 'col_articles',
    fields: {
        id: new UuidField({ primary: true, auto: true }),
        title: new StringField({ id: 'fld_articles_title' }),
        body: new StringField({ id: 'fld_articles_body', length: 65535 }),
        author: new M2OField({ id: 'fld_articles_author', to: directusUsers }),
        date_created: new TimestampField({ id: 'fld_articles_created' }),
    },
});

export default {
    schema: new Schema([articles]),
    auth: new EnvAuthProvider({
        urlEnv: 'DIRECTUS_URL',
        tokenEnv: 'DIRECTUS_TOKEN',
    }),
    vendor: 'postgres',
};
npx ddk diff           # preview the plan
npx ddk apply          # plan + confirm + execute
npx ddk apply --auto-approve   # CI

CLI

Command Purpose
ddk init Scaffold a starter ddk.config.ts in the current directory
ddk synth Emit the desired schema state (DDK or Directus snapshot format)
ddk diff Print the apply plan without executing
ddk apply Run plan + confirm + execute
ddk sync-state Rebuild .ddk/state.json from live Directus
ddk types Emit a typed Schema TypeScript file for SDK consumers

Run ddk <command> --help for command-specific options.

Consuming the schema from the Directus SDK

Cross-package consumers (a Next.js app, a mobile client, a separate microservice) get a typed Schema via a static .ts file:

npx ddk types --out ./directus-schema.ts

Or auto-emit on every successful apply by setting typesOut in ddk.config.ts:

export default {
    schema: new Schema([articles]),
    auth: new EnvAuthProvider({ ... }),
    vendor: 'postgres',
    typesOut: './directus-schema.ts',
};

Then in the consumer package:

import { createDirectus, rest } from '@directus/sdk';
import type { DirectusSchema } from './directus-schema';

const client = createDirectus<DirectusSchema>('https://cms.example.com').with(
    rest(),
);

The emitted file has no runtime DDK dependency — it's pure import type, so consumer bundlers tree-shake it to a type-only artifact. Commit the file and gate CI on ddk types --check to catch drift. See Concepts §4 for the full story.

Documentation

License

MIT