Platform and utilities
This page covers the surfaces that are adjacent to the system-collection model but do not fit neatly into the row-backed CRUD pattern most of the system collections follow. Some of these are technically system collections (directus_settings is one row in directus_settings), but most are operational endpoints that expose platform state or perform one-shot operator actions.
If you are looking for /items-style collection CRUD, this is not the page. Read each section’s intro to know what shape to expect.
Settings (/settings)
Section titled “Settings (/settings)”directus_settings is a singleton: there is one row, and it holds project-wide configuration that the admin app reads on every page load. Branding, default storage, asset transform policies, password policy, login attempt limits, and a few other operator-managed values live here.
Endpoints
Section titled “Endpoints”| Method | Path | Purpose |
|---|---|---|
GET | /settings | Read the settings singleton. |
PATCH | /settings | Upsert the settings singleton (creates the row on first call, updates it thereafter). |
There is no POST /settings or DELETE /settings. The row is conceptually permanent; the platform creates it on demand the first time PATCH /settings is called.
Settings record fields
Section titled “Settings record fields”The settings row carries dozens of fields. The notable ones:
project_name,project_descriptor,project_url,project_logo,project_color— branding shown in the admin app and in transactional emails.public_foreground,public_background,public_note,public_favicon— branding for the public-facing login screen.default_language,default_appearance,default_theme_light,default_theme_dark— default per-user preferences for new accounts.auth_password_policy— the password complexity regex.auth_login_attempts— count of failed logins before lockout. Default25.storage_asset_transform,storage_asset_presets— control which asset transformations the platform accepts. See Files / Image transformations.storage_default_folder— folder UUID that uploads default into when no folder is specified.mapbox_key— token for the map layout’s tile provider.module_bar— array of module IDs and ordering for the admin app’s module bar.custom_css— inline CSS injected into the admin app, used for branding and small UI overrides.custom_aspect_ratios— operator-defined aspect ratios for image transforms.
PATCH /settings accepts a partial body; only the fields you include are touched. Operators rarely write the full row.
Server (/server/*)
Section titled “Server (/server/*)”The /server subtree exposes platform state and machine-readable specifications. None of these routes touch a row in the database in a write sense; they are read-only operator and tooling routes.
Endpoints
Section titled “Endpoints”| Method | Path | Purpose |
|---|---|---|
GET | /server/info | Project info, version, and feature flags. |
GET | /server/health | Liveness and readiness checks across database, cache, rate limiter, storage, and email. |
GET | /server/specs/oas | The platform’s OpenAPI 3 specification, dynamically generated from the running schema. |
GET | /server/specs/graphql/<scope> | The GraphQL SDL for one of the two endpoints. <scope> is items (default) or system. |
GET /server/info
Section titled “GET /server/info”Returns a data envelope whose contents depend on the caller’s accountability:
- Unauthenticated callers receive only the public branding subset:
project.project_name,project_descriptor,project_logo,project_color,default_language,public_foreground,public_background,public_note, andcustom_css. This is what the admin app reads on the login screen before the user has authenticated. - Authenticated users additionally receive
rateLimitandrateLimitGlobalblocks describing the configured rate-limiter policy. - Admins additionally receive
cairncms.version, anodeblock (Node version and uptime), and anosblock.
The platform version is admin-only on this endpoint. Clients that need to detect the running version without admin credentials should look at the package’s published version channel rather than reading it from /server/info.
GET /server/health
Section titled “GET /server/health”Returns a health-check payload following the application/health+json convention. The response includes overall status (ok, warn, error) and per-subsystem checks for database, cache, rate limiter, storage, and email. The HTTP status is 200 on ok or warn and 503 on error. The endpoint opts out of caching, so each call reflects current state.
The endpoint is unauthenticated for the overall status and gated behind admin access for the per-subsystem detail. Use this as a load balancer health probe and as the entry point for operator monitoring.
GET /server/specs/oas
Section titled “GET /server/specs/oas”Generates an OpenAPI 3 document for the running deployment. The spec includes every collection (user-defined and system) that the requesting role can read, with collection-tagged paths filtered by per-collection permissions. Tags that do not represent a collection (Server, Utilities, Extensions, Schema, Auth, and so on) are included unconditionally. So /utils/cache/clear shows up in the spec for every caller, even though only admins can successfully invoke it. Use the per-route descriptions and the underlying permission model to understand which calls will succeed; do not infer reachable surface from spec inclusion alone.
Useful for code generators (openapi-generator, openapi-typescript), API explorers (Swagger UI, Redoc), and any tooling that consumes OpenAPI to scaffold client code.
GET /server/specs/graphql/<scope>
Section titled “GET /server/specs/graphql/<scope>”Returns the GraphQL SDL for one of the two GraphQL endpoints, served as a .graphql attachment. Pass <scope> as items (the user-collection root at /graphql) or system (the system-collection root at /graphql/system). Omitting the scope defaults to items.
The downloaded file works with code generators (graphql-codegen) and any GraphQL-aware tooling. The SDL is generated dynamically against the running schema and the requesting role’s permissions, so the same caveat as OpenAPI applies: two roles see different SDLs from the same deployment.
This endpoint is gated by GRAPHQL_INTROSPECTION. When introspection is disabled, the endpoint returns a 403, alongside the corresponding rejection on __schema and __type queries. See GraphQL / Schema introspection.
Extensions (/extensions/*)
Section titled “Extensions (/extensions/*)”The /extensions subtree exposes the platform’s installed extensions. There is no directus_extensions table; extensions live on disk and are discovered at startup. The endpoints expose the discovered set, plus the JavaScript chunks the admin app loads at runtime.
Endpoints
Section titled “Endpoints”| Method | Path | Purpose |
|---|---|---|
GET | /extensions/<type> | List installed extensions of a given type. |
GET | /extensions/sources/<chunk> | Fetch the bundled JavaScript chunk for app extensions. |
<type> is the pluralized name of any of the nine extension types: interfaces, displays, layouts, modules, panels, hooks, endpoints, operations, bundles. An invalid type returns 404 ROUTE_NOT_FOUND.
GET /extensions/<type>
Section titled “GET /extensions/<type>”Returns an array of ExtensionInfo objects describing installed extensions of the given type. The admin app uses this to populate the picker in field-configuration drawers (for interfaces and displays) and the panel-type picker on dashboards.
GET /extensions/interfaces{ "data": [ { "name": "my-color-picker", "type": "interface", "local": false, "version": "1.2.0", "host": "^1.0.0", "entries": [] } ]}Each entry has name, type, local (whether the extension was discovered from a local path or from node_modules), and entries (populated for bundle extensions to describe their constituent extensions). The optional version and host fields appear when the extension’s package.json declares them.
GET /extensions/sources/<chunk>
Section titled “GET /extensions/sources/<chunk>”Serves the bundled JavaScript code for installed app extensions. The admin app calls /extensions/sources/index.js at boot to load every app-side extension’s code, plus follow-up calls to load chunks named by the manifest. The response is application/javascript with a Cache-Control header derived from EXTENSIONS_CACHE_TTL.
Operators rarely call this directly. It exists for the admin app’s runtime loader.
Utils (/utils/*)
Section titled “Utils (/utils/*)”The /utils subtree is a grab bag of operational helpers that don’t fit anywhere else. Most are admin-only, and most are one-shot actions rather than CRUD on a resource.
Endpoints
Section titled “Endpoints”| Method | Path | Purpose |
|---|---|---|
GET | /utils/random/string | Generate a random URL-safe string. |
POST | /utils/hash/generate | Argon2-hash a string. |
POST | /utils/hash/verify | Verify a string against an Argon2 hash. |
POST | /utils/sort/<collection> | Reorder items in a sortable collection. |
POST | /utils/revert/<revision-id> | Revert an item to a specific revision. |
POST | /utils/import/<collection> | Import items from a CSV or JSON file (multipart upload). |
POST | /utils/export/<collection> | Async export of a query result to a file in the configured storage backend. |
POST | /utils/cache/clear | Flush the platform’s caches. Admin-only. |
GET /utils/random/string
Section titled “GET /utils/random/string”GET /utils/random/string?length=24Returns { "data": "<random-string>" }. The length query parameter is optional; the default is 32 and the maximum is 500.
POST /utils/hash/generate and POST /utils/hash/verify
Section titled “POST /utils/hash/generate and POST /utils/hash/verify”Generate and verify Argon2 hashes against arbitrary strings. Useful when an external system needs to interoperate with the platform’s password hashes.
POST /utils/hash/generateContent-Type: application/json
{ "string": "<plaintext>" }Response: { "data": "<argon2-hash>" }.
POST /utils/hash/verifyContent-Type: application/json
{ "string": "<plaintext>", "hash": "<argon2-hash>" }Response: { "data": true | false }.
POST /utils/sort/<collection>
Section titled “POST /utils/sort/<collection>”Reorders items in a collection that has a sort field configured.
POST /utils/sort/articlesContent-Type: application/json
{ "item": "<id-of-item-being-moved>", "to": "<id-of-the-item-it-should-end-up-before>" }The platform updates the sort values on the affected rows so that the moved item lands immediately before the target item. Returns 200 with no body.
POST /utils/revert/<revision-id>
Section titled “POST /utils/revert/<revision-id>”Reverts the item described by the named revision to that revision’s state. The operation produces a new activity row and a new revision row recording the revert, so the audit trail stays consistent. See Activity and revisions / Reverting for the full reference.
POST /utils/import/<collection>
Section titled “POST /utils/import/<collection>”Accepts a multipart upload of a CSV or JSON file and imports the rows into the named collection. The MIME type of the file part determines how the contents are parsed.
POST /utils/import/articlesContent-Type: multipart/form-data; boundary=...
------boundaryContent-Disposition: form-data; name="file"; filename="articles.csv"Content-Type: text/csv
<csv contents>------boundary--The endpoint returns 200 with no body when the import completes. Errors during import (validation failures, foreign key violations, malformed rows) abort the import and return a standard error envelope.
POST /utils/export/<collection>
Section titled “POST /utils/export/<collection>”Exports a query result to a file in the configured storage backend. Unlike the other utility endpoints, this runs asynchronously: the request returns immediately and the export proceeds in the background.
POST /utils/export/articlesContent-Type: application/json
{ "query": { "filter": { "status": { "_eq": "published" } }, "fields": ["id", "title", "author.name"] }, "format": "csv", "file": { "folder": "<folder-id>" }}Body fields:
query(required) — the same query DSL used forGET /items/<collection>(see Filters and queries).format(required) —csv,json,xml, oryaml.file(optional) — metadata for the resultingdirectus_filesrow. Useful for placing the export in a specific folder.
The export creates a new file in directus_files with the result content. Watch directus_files for the new row to know when the export has finished.
POST /utils/cache/clear
Section titled “POST /utils/cache/clear”Flushes every cache the platform maintains: response cache, schema cache, permissions cache. Admin-only; non-admin callers get 403 FORBIDDEN.
POST /utils/cache/clearReturns 200 with no body. Useful after schema changes that the cache might not have picked up automatically, or as a debugging step when stale data is suspected.
Permission semantics
Section titled “Permission semantics”The collections and endpoints on this page span the permission model:
directus_settings— read access is broadly granted by default so the admin app can render branding and pick up project preferences. Write access is admin-only by default./server/info,/server/health, and the spec routes — operator-facing rather than collection-CRUD. The basic/server/infoand/server/healthendpoints do not require authentication; spec generation and the per-subsystem/server/healthdetail are scoped to admin-readable schema./extensions/<type>and/extensions/sources/<chunk>— reachable without authentication. The routes sit behind the global authenticate middleware, but that middleware allows anonymous requests by assigning a default accountability, and the extensions controller does not add any further permission gate. The admin app loads these endpoints on its login screen before the user has authenticated, which is why they need to work unauthenticated. If your extension manifest reveals sensitive metadata, treat the endpoint as effectively public./utils/*— varies.random/stringandhash/*are unauthenticated.sort,revert,import, andexportrequire accountability and are gated by per-collection permissions.cache/clearis admin-only.
GraphQL
Section titled “GraphQL”The settings collection appears on /graphql/system with singleton-shaped resolvers: a settings query that calls readSingleton and an update_settings mutation that calls upsertSingleton. There is no settings_by_id or batch-create / batch-delete; the GraphQL surface mirrors the REST GET /settings and PATCH /settings shape.
The server queries (server_info, server_health, server_ping, server_specs_oas, server_specs_graphql) live on /graphql/system as ordinary queries. See GraphQL / What /graphql/system exposes for the full list.
/graphql/system also exposes an extensions query that returns the installed app-side extensions (interfaces, displays, layouts, modules) as nested string arrays. It does not cover hooks, endpoints, operations, or bundles, and there is no GraphQL equivalent of /extensions/sources/<chunk> (the bundled-JS loader is REST-only by necessity).
The rest of /utils is REST-only. There is no GraphQL equivalent for cache flushing, asset import / export, sort, revert, hash generation, or random string generation.
Where to go next
Section titled “Where to go next”- Configuration — environment variables that complement many of the settings on this page (storage, mail, rate limiting, cache).
- Activity and revisions — the revision model that
POST /utils/revert/<revision-id>operates on. - Files — the asset surface that interacts with the export endpoint and the
storage_*settings. - Schema as code — the
/schema/*endpoints that share an admin-operator role with/utils/cache/clear.