npm-workspaces monorepo, built with Turborepo and released with Changesets, using linked versioning (packages released together share one version number; a package nobody touched keeps the version it had). It contains two npm packages:
packages/sdk→datocms-plugin-sdk— core TypeScript SDK for building DatoCMS pluginspackages/react-ui→datocms-react-ui— React components mimicking the DatoCMS UI; depends ondatocms-plugin-sdk
npm install # workspaces: one install at the root wires up both packages
npm run build # turbo; builds in dependency order (sdk before react-ui), and caches
npm test # Jest unit tests
npm run format # biome check + format
npx changeset # describe a change for the next release (commit the file it writes)Each package has an install-in-place script that rebuilds that package only and copies its artifacts over the installed copy in a plugin project:
cd packages/<pkg> && INSTALL_PATH=/path/to/plugin npm run install-in-placeUse it instead of npm link (a symlinked React library breaks with duplicate-React "Invalid hook call" errors). If a change spans both packages, run the sdk's script before react-ui's — react-ui compiles against the sdk's build output.
- Every user-visible change needs a changeset (
npx changeset) in the same PR, or it ships with no release note.patchis for bug fixes only; new API surface isminor. - Releasing (maintainers only):
npm run releasefrom the root, on a cleanmaster. It builds and tests, applies the pending changesets, publishes to npm, then tags, pushes, and opens the GitHub releases. An interrupted release is resumed by re-running it, never undone. The script is@datocms/release-toolchain, shared by every DatoCMS repository and pinned here by git tag. - One
name@X.Y.Ztag and one GitHub release per package.changeset publishdoes the publishing and the tagging itself, in that order and only for the packages npm accepted, so a tag can't outlive a failed publish. What is being released comes fromchangeset publish-plan --output, not from anything the script reconstructs. Each release's body is that package's ownCHANGELOG.mdsection — when a package moved only because the other one did, that section is just its dependency bump, which is the honest thing to show. Releases up to v2.2.7 used a singlevX.Y.Ztag instead; those tags stay where they are.
packages/react-ui/AGENTS.md— react-ui architecture (CSS Modules JSON pipeline, dual CJS/ESM output, theming viactx)- Each package README has a human-facing "Developing" section; keep them in sync with these files.