Directus, the license and the limits over your SQL database
Directus connects to a SQL database you already have, reads its structure, and puts an admin panel plus a REST and GraphQL API on top of it. Version 12.3.0, released on 18 August 2026, brought something you need to settle before deployment: a custom license and a license key that hard-enforces limits on seats, collections, and flows.
The license file no scanner will find
Start with the thing that breaks automated dependency audits. In the root of the directus/directus repository the license file is named license, lowercase and without an extension. Every spelling a typical scanner looks for returns 404.
# as of 22 August 2026, main branch
for f in license LICENSE LICENSE.md license.md LICENSE.txt COPYING NOTICE LICENSING.md; do
curl -s -o /dev/null -w "$f -> %{http_code}\n" \
"https://raw.githubusercontent.com/directus/directus/main/$f"
done
# license -> 200
# LICENSE -> 404
# LICENSE.md -> 404
# license.md -> 404
# LICENSE.txt -> 404
# COPYING -> 404
# NOTICE -> 404
# LICENSING.md -> 404In the npm registry, package directus version 12.3.0 declares "license": "SEE LICENSE IN license". That is the SPDX escape hatch, used when terms cannot be expressed as an identifier. A tool expecting a value like MIT or Apache-2.0 gets a string with no machine meaning here and will either skip it or flag it as unknown. Up to and including 11.17.4 the field held BUSL-1.1, a valid identifier scanners recognised. The field changed in 12.0.0, published on 10 June 2026.
It is worth checking what actually ships in the published tarball, because it surprises.
curl -sL https://registry.npmjs.org/directus/-/directus-12.3.0.tgz -o directus.tgz
tar tzf directus.tgz
# package/version.d.ts
# package/license
# package/version.js
# package/readme.md
# package/package.json
# package/cli.js
# the archive is 4975 bytes; no application code lives here
tar xzf directus.tgz && cat package/cli.js
# import { updateCheck } from '@directus/update-check';
# import { version } from './version.js';
# if (version) { await updateCheck(version); }
# import('@directus/api/cli/run.js');The directus package is a shim over two dependencies: @directus/api version 39.0.0 and @directus/update-check version 14.0.0. The whole server sits in the first one, which unpacks to 2,221,948 bytes across 847 files. The license file inside the tarball is byte-for-byte identical to the one in the repository, which I verified with diff. The declaration matches the contents, except that the declaration points at a file rather than at an identifier.
Monospace Sustainable Core License 1.0, clause by clause
Inside the license file is a text titled "Monospace Sustainable Core License, Version 1.0" with the custom abbreviation MSCL-1.0-GPL and the notice "Copyright 2026 Monospace Inc.". This is a bespoke license written by the company behind Directus. It is not the Business Source License, not the Elastic License, and not the Server Side Public License. The same text is published at directus.com/license.
The heart of it fits in two paragraphs. The license grants the right to use, copy, modify, create derivative works, and redistribute, but only for a "Permitted Purpose". And Permitted Purpose is defined by negation: it is any purpose other than a "Competing Use". Competing Use means making the software available to any party, standalone or together with your own products or services, in a way that competes with Directus's own commercial offerings of the software, where Monospace charges a license fee, royalty, or other charge for it.
The text names four permitted purposes explicitly: internal use and access, non-commercial education, non-commercial research, and professional services provided to a licensee who is itself using the software under these terms, including deploying and hosting it for that licensee. The last point matters for agencies: you may stand up and maintain Directus for a client, because the client is the licensee.
One thing has to be said plainly, because a reader hunting for a "threshold" in the license text will not find one: MSCL 1.0 contains no numeric threshold at all. No user cap, no revenue floor, no headcount ceiling. The boundary is the kind of use, not the scale. The numbers that actually constrain free use live in two other places: in the license key enforced by the code, and in the Open Innovation Grant terms on the vendor's site. Both are covered below.
The remaining clauses, briefly. The Limitations section forbids moving, changing, disabling, or circumventing the license key functionality, and forbids modifying code it protects in order to unlock functionality without a valid key or to remove the restriction. The Patents section grants a patent license within the permitted scope and terminates it immediately if you assert a patent claim against anyone over this software. The Redistribution section extends the terms to all copies and derivatives, requires you to include the license text or a link to it, requires you to keep copyright notices, and forbids imposing further restrictions, including fees of your own. The Trademarks section grants no rights to trademarks beyond identifying the origin of the software.
A conversion date exists and it rolls. The "Grant of Future License" clause irrevocably grants an additional GPL-3.0 license, effective on the fourth anniversary of the date that version was made available. There is no single date for the whole project: every release has its own clock. Version 12.3.0, made available on 18 August 2026, becomes available under GPL-3.0 on 18 August 2030, counting from the registry publication date.
The licensing history looks like this. Up to and including 9.26.0 the license file held the full text of the GNU GPL v3. From 10.0.0 it was Business Source License 1.1 with an additional production grant for parties whose "Total Finances", meaning the largest of gross revenue, entire budget, or funding, did not exceed 5,000,000 US dollars over the most recent twelve months, with a Change Date of three years from the release date and a Change License of GPL v3. The same arrangement held in 11.0.0, released on 6 August 2024. In 12.0.0 MSCL replaced BSL. The change has two practical effects: the revenue threshold disappeared from the license text, and the wait for open code grew from three years to four.
The license key and the hard limits of the Core plan
Without a key, Directus 12 runs on a built-in entitlement set named Core. That set is written into the @directus/license package, which is MIT-licensed, so you can read it directly.
{
"meta": {
"offline": true, "grace_period": -1, "name": "Core",
"validation_interval": -1, "expires_at": -1
},
"entitlements": {
"seats": { "limit": 3 },
"collections": { "limit": 25 },
"flows": { "limit": 5 },
"sso_enabled": { "default": false },
"activity_historical_timeframe": { "limit": 2592000 },
"revision_historical_timeframe": { "limit": 2592000 },
"telemetry_required": { "default": true },
"offline_enabled": { "default": true },
"custom_llms_enabled": { "default": false },
"custom_permission_rules_enabled": { "default": false },
"display_powered_by": "DIRECTUS",
"production_enabled": { "default": true },
"ai_translations_enabled": { "default": false }
}
}Three seats, twenty-five collections, five flows. The value 2,592,000 seconds is exactly thirty days of activity log and revision history. production_enabled is true, so free Core may be used in production. telemetry_required is true, and telemetry opt-out appears in the pricing table as an Enterprise feature. display_powered_by set to DIRECTUS means vendor branding in the panel.
The counting is more forgiving than it looks, and that changes the arithmetic for projects on a large database. A seat is consumed only by a user with status active whose policy grants admin_access or app_access, meaning someone who signs in to Directus Studio. Accounts that only call the API with a token consume no seat. Collections are counted after filtering out system collections, folders, entries with a status other than active, tables listed in the DB_EXCLUDE_TABLES variable, and, most importantly, tables present in the database but not registered in Directus. A table shown in the panel as "database only" does not count toward the twenty-five. A database with three hundred tables fits inside Core as long as you expose at most twenty-five of them through Directus.
Exceeding the limit has a concrete effect. Once the license state is computed as locked, the is-locked middleware throws ResourceRestrictedError in the items, files, assets, graphql, flows, and mcp controllers. That means the public content API stops responding, not just the panel. Installations upgraded from version 11 get a grace period: 720 hours, that is thirty days, counted from the timestamp of migration 20260507A. Fresh installations do not get it; they are identified by less than twenty-four hours passing between the oldest migration and the licensing migration.
The key is supplied through the LICENSE_KEY or LICENSE_TOKEN variable. Setting both at once produces a fatal log entry and terminates the process. Without the variables, Directus reads the license_key and license_token columns from the directus_settings table.
The @directus family carries two licenses at once
Within the @directus npm scope the license is not uniform, and that is good news for anyone building a client or extensions on Directus.
On MSCL, with the field SEE LICENSE IN license, are: directus 12.3.0, @directus/api 39.0.0, @directus/app 17.1.0, @directus/schema 14.0.2, and @directus/storage 13.0.0. On MIT are, among others: @directus/sdk 25.0.0, @directus/extensions-sdk 18.0.3, @directus/types 16.2.0, @directus/composables 11.6.1, @directus/themes 2.0.3, @directus/system-data 4.6.0, @directus/errors 2.5.1, @directus/env 6.2.1, @directus/constants 14.4.1, @directus/ai 1.3.2, and @directus/update-check 14.0.0. The SDK your frontend application uses is therefore permissive; the restrictions apply to the server and the panel.
Two entries in that list deserve a comment. The @directus/license package, which holds the CORE_LICENSE constant, declares MIT, but the 0.4.0 tarball contains no license file whatsoever: only README.md, a dist directory, and package.json. The second issue is a version skew inside the family. @directus/api 39.0.0 pins @directus/license firmly at 0.4.0, while the registry's newest version of that package is 0.5.6 from 30 July 2026. This is a pin, not a peer dependency range, so installation will not break, but an audit will report a package older than the one available.
Separately: every release in the 9.x line is marked deprecated in the registry with the message "Version no longer supported. Upgrade to @latest.". The esu tag points at 10.13.4 and the canary tag at 12.0.0-rc.2.
What Directus does to your schema
This question decides whether Directus is a tool bolted next to your database or a tool that absorbs it. The answer: it adds its own tables alongside yours and leaves yours alone, until you yourself tell it to create fields through the panel.
During directus bootstrap the seeds and one hundred and seven migrations run, creating a set of tables with the directus_ prefix. There are thirty-three: directus_access, directus_activity, directus_collections, directus_comments, directus_dashboards, directus_deployment_projects, directus_deployment_runs, directus_deployments, directus_extensions, directus_fields, directus_files, directus_flows, directus_folders, directus_migrations, directus_notifications, directus_oauth_clients, directus_oauth_codes, directus_oauth_consents, directus_oauth_tokens, directus_operations, directus_panels, directus_permissions, directus_policies, directus_presets, directus_relations, directus_revisions, directus_roles, directus_sessions, directus_settings, directus_shares, directus_translations, directus_users, and directus_versions. All of them must live in the same database as your data, because Directus connects through a single knex connection.
Metadata about your tables, meaning display names, field interfaces, and relations, goes into directus_collections, directus_fields, and directus_relations. Your own tables get no extra columns. Walking away from Directus is therefore possible and comes down to dropping the prefixed tables; the database is left as it was, minus the panel configuration.
# .env
DB_CLIENT="pg" # knex values: pg, mysql, sqlite3, oracledb, cockroachdb, mssql
DB_HOST="localhost"
DB_PORT="5432"
DB_DATABASE="my_existing_database"
DB_USER="directus"
DB_PASSWORD="..."
DB_EXCLUDE_TABLES="spatial_ref_sys,audit_log" # default: spatial_ref_sys
LICENSE_KEY="" # empty = built-in Core entitlement set
KEY="..."
SECRET="..."npx directus bootstrap # seeds and migrations, creates an admin
npx directus database migrate:latest # system schema update only
npx directus schema snapshot ./snap.yaml
npx directus schema apply --dry-run ./snap.yaml
npx directus schema apply -y --ignoreRules "reports,orders.note"
npx directus count orders
npx directus users create --email a@b.com --password ... --role <uuid>
npx directus cache clear --systemThe schema snapshot and schema apply pair is how you move configuration between environments. The --dry-run flag prints the planned changes without applying them, and --ignoreRules takes a comma-separated list of collections and fields to skip. Node 22 or newer is required, as declared by the engines field in both directus and @directus/api. Database drivers are optional dependencies: pg, mysql2, sqlite3, oracledb, and tedious.
-- leaving Directus: your tables stay untouched
DROP TABLE IF EXISTS
directus_activity, directus_revisions, directus_sessions,
directus_permissions, directus_access, directus_policies,
directus_fields, directus_relations, directus_collections,
directus_users, directus_roles, directus_settings,
directus_files, directus_folders, directus_flows,
directus_operations, directus_migrations
CASCADE;Cloud and self-hosted pricing
The pricing page at directus.com/pricing renders without JavaScript, so the figures below come from the raw page source fetched on 22 August 2026.
The Core plan costs 0 dollars and gives 3 seats, 25 collections, 5 flows, the AI assistant, advanced role-based access control, community support, and 30 days of activity log and revision retention. The Team plan costs 499 dollars per month on an annual commitment, which the page states as 5,988 dollars per year, or 599 dollars per month with no commitment. The arithmetic checks out: 499 times 12 is exactly 5,988. Monthly billing therefore costs 7,188 dollars a year, which is 1,200 more. Team includes 10 seats with single sign-on, 50 collections, 20 flows, granular roles, basic support, and 90 days of retention. An extra seat costs 50 dollars per month, extra collections 100 dollars per pack of 25. The Enterprise plan is priced on request and covers, among other things, SAML and OIDC, a custom language model, offline mode, AI translations, telemetry opt-out, and configurable retention.
Cloud is not a separate plan but an add-on: 99 dollars per month for Core and for Team, custom pricing for Enterprise. Self-hosting is available at every tier.
The third route is called the Open Innovation Grant, and it is the real answer to the question of who may use Directus for free without limits. Organisations under 5,000,000 dollars of annual revenue and under fifty employees qualify, as do individuals, non-profits, and hobbyists. The grant gives unlimited seats, collections, and flows, single sign-on, a custom language model, and AI translations. Self-hosting is then free of charge and cloud costs the same 99 dollars per month for hosting alone. The key is issued on application, and the vendor reserves the right to revoke it if the information given was false.
On the revenue threshold the vendor states two different values, and that has to be recorded. The FAQ on the pricing page says "under $5M in annual revenue", meaning annual revenue, while the directus.com/oig page says "under $5M annual recurring revenue", meaning recurring revenue. For a company with a mixed sales model that difference matters, and it is worth clarifying before applying. A smaller discrepancy concerns Team collections: the table says 50, while the FAQ answer speaks of 50 expandable to 100.
For customers who signed up before the pricing change, the page promises transitional treatment: monthly plans held for six months, annual plans honoured until renewal, self-hosted licenses handled case by case at renewal.
Directus against Strapi, Payload, Sanity, and Contentful
There is one fundamental difference. Strapi, Payload CMS, and Sanity define their own content model, and the database schema is a by-product of that model. Directus works the other way round: it takes the schema that already exists and builds a layer on top. If you have a PostgreSQL database serving an application and want to give your editors a panel over three tables, Directus is the only one of the four that does not make you rewrite the model. If you are starting from scratch and the content model is still being designed, that advantage disappears.
| Tool | Server code license | Schema model | Free usage |
|---|---|---|---|
| Directus 12.3.0 | MSCL-1.0-GPL, bespoke, GPL-3.0 after 4 years | reads existing SQL tables | 3 seats, 25 collections, 5 flows |
| Strapi 5.52.1 | MIT with a separate license in ee/ directories | generates its own tables | no seat limit in the MIT core |
| Payload 3.88.0 | MIT | generates its own tables | no limit, MIT throughout |
| Sanity 6.10.1 | MIT on the Studio side, closed backend | own document model | plan limits in the hosted service |
| Contentful | no code available for self-hosting | own content model | plan limits in the hosted service |
Comparing licenses is a genuine selection factor in this category. Payload is MIT throughout, so the question goes away. Strapi keeps its core on MIT and closes commercial terms inside ee/ directories, where the file is named LICENSE in capitals and the npm field for @strapi/strapi 5.52.1 reads SEE LICENSE IN LICENSE. Sanity and Contentful are hosted services, where the question of server code licensing does not arise, because you never receive that code.
If you want a backend with an API generated from the database and without restrictions of this kind, the sensible directions are Supabase, where PostgREST exposes an API straight from PostgreSQL, and PocketBase for smaller deployments on SQLite.
Common mistakes
First: concluding that because the repository is public and visible on GitHub, the code is open. MSCL does not meet the Open Source Initiative definition, because it restricts the purpose of use. Directus 12 is source-available software.
Second: assuming your dependency scanner's output is complete. The SEE LICENSE IN license field plus the lowercase filename are enough to leave a blank cell in a license report. In this case the entry in your license register has to be made by hand.
Third: counting collections by the number of tables in the database. The limit applies to registered and active collections, not to everything Directus can see in the schema.
Fourth: upgrading from version 11 to 12 in production without checking how many seats and collections are in use. The thirty-day grace period ends in the locked state, and then items, files, assets, graphql, flows, and mcp stop responding.
Fifth: setting LICENSE_KEY and LICENSE_TOKEN at the same time. The process exits immediately with a fatal entry.
Sixth: assuming the license text carries a revenue threshold, as the Business Source License did. It does not. The 5 million dollar threshold belongs to the Open Innovation Grant and is a vendor programme condition, not a license clause.
FAQ
Can I use Directus 12 commercially for free?
Yes, within the Core entitlement set: 3 panel seats, 25 active collections, 5 flows, no single sign-on, and 30 days of activity history. The license does not forbid production use, which the production_enabled entry set to true confirms. What is forbidden is reselling Directus as a service competing with Monospace's own offering.
How does MSCL differ from the Business Source License Directus used before?
BSL 1.1 in versions 10 and 11 permitted production use below 5 million dollars of "Total Finances" and opened the code under GPL v3 after three years. MSCL removes the financial threshold from the license text, replaces it with a restriction on the kind of use plus a license key, and extends the wait for open code to four years from each version's release.
Will Directus ever become fully open?
Each release separately. The Grant of Future License clause irrevocably grants a GPL-3.0 license on the fourth anniversary of the date that version was made available. There is no single project-wide date, only a rolling clock per release.
Will Directus modify my existing tables?
No, not until you add fields through the panel yourself. Installation creates 33 tables prefixed with directus_ in the same database and keeps all metadata there. Dropping those tables leaves your schema as it was before installation.
What does the Team plan actually cost?
499 dollars per month on an annual commitment, which is 5,988 dollars per year, or 599 dollars per month with no commitment, which is 7,188 dollars per year. Cloud hosting is a separate 99 dollars per month.
Who qualifies for the Open Innovation Grant?
Organisations under 5 million dollars of annual revenue and under 50 employees, plus individuals, hobbyists, and non-profits. The grant removes the seat, collection, and flow limits for self-hosting. The vendor states the threshold once as annual revenue and once as annual recurring revenue, so it is worth confirming that definition before applying.