Product

|

Directus v12.3: Sync Your Schema Across Environments With the New Directus CLI

Version-controlled schema sync between dev, staging, and production, plus hardened storage connections and safer flow operation defaults.

Bryant Gillespie

Staff Product Engineer

You can now sync schema and configuration between Directus instances from the command line, through JSON files you commit to your repo. This has been one of the most requested capabilities in Directus for a long time, and it's here in v12.3.

The release also hardens asset delivery with improved storage connection handling and adds safer defaults to two flow operations.

Before we dive in, I want to highlight a few potential breaking changes you should be aware of, though:

Breaking Changes

🟡 "Update Items" and "Delete Items" flow operations no longer target every row: Previously, leaving both the key and query empty on these operations would update or delete every item in the collection. Now they do nothing and return null. If you have flows that relied on the old fallback, add {"limit": -1} to explicitly target everything.

🟡 exists() now throws on lookup failures: As part of the storage driver fixes below, exists() throws an error on genuine lookup failures instead of silently returning false. If your extensions call it directly, make sure you're handling that.

🟡 Image transform output limit raised to 6000px: ASSETS_TRANSFORM_IMAGE_MAX_OUTPUT_DIMENSION now matches ASSETS_TRANSFORM_IMAGE_MAX_DIMENSION at 6000px by default. If you were counting on the old 3000px ceiling, set it explicitly.

🟡 Docker entrypoint change: Docker images now boot via node docker-entrypoint.cjs. If you have a custom CMD that calls pm2-runtime directly, hand off to docker-entrypoint.cjs instead. pm2 itself stays on the PATH for docker exec diagnostics.

Environment Sync: Schema as Code

Directus v12.3 - Environment Sync

Any project that spans dev, staging, and production comes with the same overhead: keeping schema in step across every environment as it evolves. Your application code already solved this problem years ago. It moves through environments in version control, with diffs, reviews, and a clear history of what changed.

Your Directus schema now works the same way.

The new @directus/cli (aliased as d6s or directus-cli) syncs schema and configuration between Directus instances through JSON files you commit to your repo.

The workflow is what you'd expect from a good sync tool. sync pull exports schema and configuration from an instance into JSON. sync diff shows you exactly what's different between your files and a target instance before you touch anything. sync push applies the changes. There's also an interactive wizard if you'd rather be walked through it.

Because everything lives in committed JSON files, your schema changes move through the same review process as your code. Pull request, review, merge, push to the next environment. Every collection, field, and setting travels with your project, and the history of what changed is right there in your repo.

The bottom line: Your schema is now version-controlled and portable across environments, managed from the command line like the rest of your stack.

More Resilient Asset Delivery Across Every Storage Driver

Storage connection handling got a meaningful upgrade in this release. Asset requests that get cancelled or fail mid-transformation now release their storage connections immediately, keeping asset delivery healthy under any traffic pattern, no matter how many requests get interrupted along the way.

The improvement applies across every storage driver: S3, GCS, Azure, Cloudinary, Supabase, and local storage.

One behavior change came with it, noted in the breaking changes above: exists() now throws on genuine lookup failures instead of silently returning false, so failures surface where you can see and handle them.

Safer Defaults for Flow Operations

The "Update Items" and "Delete Items" flow operations now treat an empty key and empty query as exactly that: empty. Instead of falling back to targeting every row in the collection, the operation returns null and does nothing. If you want to target every item, you say so explicitly with {"limit": -1}.

This is the right default. Broad operations should always reflect clear intent, and now they do. If you have existing flows that relied on the old fallback, add the explicit limit and they'll work exactly as before.

Search-First Tool Discovery for Chat and MCP

Chat and the MCP server now discover tools through search first instead of loading everything up front. The schema tool is pinned as a root-level chat tool by default, so structural questions about your data stay fast.

If you're connecting AI tools to Directus through MCP, this means leaner context and better tool selection as your instance grows. We also updated MCP tool descriptions and safety annotations for connector clients, so external AI tools get clearer signals about what each tool does and how carefully to treat it.

Security Updates

Two rounds of dependency updates in this release close out known security advisories, including GHSA-rgw5-rvv9-x895 and additional CVEs. No action needed beyond updating.

Other Improvements

  • WYSIWYG image captions: The image drawer now includes a caption field that wraps your image in a proper figure with a figcaption.

  • Block-level custom formats in WYSIWYG: Custom Formats entries with block, selector, and items now apply classes and attributes to paragraphs, headings, and other block nodes straight from the Formats dropdown.

  • Collection name in item headers: Item and drawer headers now append the collection name to the display template, so you always know what you're looking at.

  • WebSocket rate limiting on shared Redis: The WebSocket limiter now accepts RATE_LIMITER_WEBSOCKETS_* overrides, including a Redis key prefix, so multi-project shared Redis setups work correctly.

  • MS SQL Server performance: Optimized schema introspection, and trigger compatibility now only kicks in when it's actually required.

  • Faster extension sync on startup: New EXTENSIONS_STORAGE_MAX_CONCURRENCY variable to control concurrent requests to remote extension storage, fixing slow startup syncs.

  • Bug fixes: Fixed relational items showing "--" for unsaved nested values, repeater sub-fields losing key and type on save, stale relational values after manual flow updates, silent failures when dragging unrecognized file types into the file library, the AI translation button only showing for admins, SSO login redirecting to the wrong page, unrestorable WYSIWYG content in the comparison modal, outdated SDK type definitions, OpenAPI spec drift, an unhandled rejection in the SDK realtime client, and more.

Check out the full release notes on GitHub for the complete changelog.

Directus v12.3 is Available Now

Update your instances to get environment sync through the new CLI, more resilient asset delivery, safer flow operation defaults, and everything else in this release.

As always, back up your database before upgrading.