Directus vs Strapi : Comparing the headless CMS features
For the past three years, I have worked with multiple teams on building their headless CMS / backends. This includes customized versions of CMS frameworks like Strapi, custom in-house built backends, Directus driven data-engines on top of existing databases and so on. Based on this experience, I attempted to evaluate the following:
How does Directus (10.x) compare to Strapi (4.x) when it comes to catering to various features that are expected from a headless open-source CMS product?
I’ll use this post to answer this question.
Disclaimer : I’m not affiliated to the creators of Strapi or Directus in any way.
1. Data Engine vs Headless CMS
Directus and Strapi are fundamentally oriented towards solving different problems. And, knowing this difference in orientation helps us choose the right fit for our requirement.
Directus is a
Data Engine. Imagine we already have a database from an employee management system (with tables like
management, etc). Directus can be set up on top of this database to enable us to have headless CMS features to deal with this data. In this way, Directus seeks to be a wrapper of CMS features on top of a database. As a result, it can co-exist with other systems on a large backend. Or, it can be introduced on top of a legacy system without requiring data migration into the new setup.
In constrast, Strapi is a
code-driven headless CMS that maintains the database schema within the code. It conceals how the data is stored within the underlying database schema and automatically handles syncing schema changes in code with the underlying database. It also comes with a feature-rich Admin UI suited to the requirements of a large team.
2. Handling of Database Schema
The difference in the way Strapi and Directus handle the database schema (Strapi - in code vs Directus - in database) affects the following capabilities:
2.1 Migrating from an existing CMS / database: Directus ✅
With Directus’s approach, using it on top of an existing CMS / backend setup / database is simpler. All we do is install Directus, point it to this existing setup and we are good to go.
In constract, Strapi requires modelling the existing database schema into Strapi’s
schema.json format and then writing custom code to migrate data into the database schema Strapi builds based on the
schema.json we created. This makes migrating an existing data-setup into Strapi more time & effort consuming.
2.2 CMS framework lock-in: Directus ✅
Because Directus just runs on top of the database schema, the issues specific to vendor lock-in are reduced with Directus. To move out of Directus, we simply stop running it on top of our database and we have our data available as is. With Strapi, unless we decide to leverage Strapi’s schema specifics, we will need to write custom scripts to migrate out of the Strapi CMS setup.
2.3 CMS framework co-living alongside other systems: Directus ✅
Since Directus doesn’t demand any changes to the existing database schema, it can be used for a subset of the tables in a larger backend setup. In this way, it can co-exist alongside other systems in a large backend setup. This cannot be done with Strapi since it controls the database schema and actively purges any tables in the underlying database that aren’t reflected in its code
2.4 Making schema changes across environments: Strapi ✅ Directus ✅
With Strapi’s approach, carrying schema changes from one environment to another (eg -
production) would simply require running the updated code in the destination environment. But, with Directus, transporting schema changes from one environment to another would require running additional steps (
npx directus schema snapshot ./path/to/snapshot.yaml and then
npx directus schema apply ./path/to/snapshot.yaml). While Directus requires an additional step to carry schema changes across environments, it is simple enough to be made part of any deployment automation workflow.
3. Versioning the content changes made via the Admin UI Directus ✅
Content versioning enables the content editor to:
- view earlier versions of an updated record.
- restore that record back to it’s earlier version.
As of Strapi 4.17.0, there is no way to view or restore an updated record back to it’s earlier version. With Directus, we can view the version history of a record and restore it back to any of the previous versions.
With v4.6, Strapi introduced the import-export feature to export specific rows of data from one Strapi CMS setup to another. This allows us to add a certain data into a non-production Strapi CMS setup and later import it into the production Strapi CMS setup. While this feature may help some cases, it is not as sufficient as a full-blown version control for records.
4. File Uploads Strapi ✅ Directus ✅
Both Strapi and Directus provide capabilities to upload to various destinations (local path, AWS S3 bucket, etc). However, there are certain differences that may matter for some implementations:
- Strapi allows us to write our own custom providers for file uploads (the code would actually upload the files). As a result, if the storage service of our choice isn’t supported by Strapi out-of-the-box, we can simply write our custom provider to make it work. Directus seems to be working in the same direction (see this issue) in the coming future (but the feature hasn’t been prioritized in over a year).
- Both Strapi and Directus allow us to organize our media uploads into folders. Directus allows us to restrict uploads for a certain tables going into certain media gallery folders. Strapi also provides granular access-control via its RBAC feature (Role-Based Access Control) that also works for media uploads.
5. Single Sign-on Directus ✅
Both Strapi and Directus provide capabilities to authenticate via various SSO providers (Google, Github, Facebook, Okta, etc). But, with Strapi - SSO is locked behind the
Enterprise Plan which is priced as
Contact Sales (read
Expensive!). With Directus, a self-hosted setup can implement SSO without paying anything.
But, other than SSO, both Strapi and Directus allow having unlimited users and roles on self-hosted setups without having to pay anything.
6. Dynamic Zones / M2A Relationships Strapi ✅
Both Strapi and Directus allow us to build records in a table that can contain very different types of data. Think, for example, a
Pages table where each page can contain one or more sections and each section can be of differen type (image section, paragraph section, title section, etc). Ability to build such dynamic records on-the-fly makes content editing very powerful.
With Directus, this can be achieved via M2A (Many-to-any) relationships. And, the same can be achieved with Strapi via Dynamic zones.
The Strapi Admin UI is more sophisticated (allows drag-and-drop re-ordering sections of the dynamic zone, allows inserting new section anywhere in the dynamic-zone). While this may appear a minor nitpick, I have found content teams with large dynamic sections heavily rely on these UI capabilities. So, if we anticipate a heavy use of the Dynamic Zones / M2A Relationships feature, Strapi should be preferred over Directus.
7. Access Control for Admin UI Features Strapi ✅
With Strapi, Admin UI users are maintained seprately from the CMS API users. It allows us to organize the Admin UI users into various roles and configure access control specific Admin UI screens, collections, plugins, individual rows of data within the collections.
In fact, Strapi’s Role based Access Control can be setup based on programmatically defined custom rules to restrict certain Admin UI users from accessing certain rows of data. For example - We can create rules so that certain Admin UI users aren’t able to view rows of data in
Salary table for other employees.
With Directus, the only access control available for the Admin UI functionalities is to either allow or disallow a user from accessing it completely. For example - Strapi allows us to create Admin users who have access to the entire Admin setup except
Media Library section. But, Directus doesn’t have any such capability to let a user have Admin access without access to the
File Library section.
8. CRUD APIs features Strapi ✅ Directus ✅
Both Strapi and Directus provide API parameters to adequately filter, sort, paginate, limit the data as required. Directus also has additional API parameters to aggregate & group the data queried via it’s Rest APIs.
9. Access-control for APIs Strapi ✅ Directus ✅
Both Strapi and Directus allow us to configure roles to have access to specific tables. Directus provides a more fine-grained control from the Admin UI here since it allows us to let the roles have access to only specific records of a table (eg: allow access to only those records where the field
currency has value
USD). While the same cannot be done from the Strapi Admin UI, we can use Strapi middlewares to code this access-control logic.
10. Internationalization Strapi ✅ Directus ✅
Both Strapi and Directus provide features to maintain records in more than one languages. Both also provide API parameters to ask for records only in a specific language.
locale as a seprate field and allows us to query, access control, etc based on this. Directus treats
language as one more field for a collection that can be have a language value as needed.
11. Customizing the CRUD API Behavior Strapi ✅ Directus ✅
Both Strapi and Directus provide hooks for us to write custom code that gets executed when the CRUD APIs for our content are invoked. So, customizations like the following can be implemented with both:
- Modifying API requests / responses as needed
- Building custom input validations.
- Emailing someone when a certain record has a certain value.
However, there is an important distinction between the two:
- Strapi provides a global
strapiobject everywhere which can be used to access any data (eg :
- With Directus, we need to call the APIs to access any data.
In some situations, the Directus approach can be less flexible and force us to expose certain data via an API to implement specific customizations. While we can keep such APIs secure behind authentication, this is still less secure than the Strapi approach which does away with a need to expose the APIs to access data for implementing hooks or other customizations.
12. Extending the CMS functionality Strapi ✅ Directus ✅
Both Strapi and Directus allow us to build the following:
- Custom fields
- Custom Admin UI screens.
- Custom API endpoints
With the above, we can extend the CMS functionality as desired. However, the UI frameworks leveraged by the two CMS is different. Directus requires us to write the Admin UI code with
vue.js whereas Strapi requires us to write the Admin UI code with
13. Popularity Strapi ✅
As of Jan 2024, the package
@strapi/strapi has ~94k weekly downloads in comparison to ~18k weekly downloads for the
directus package. Also, as per npmtrends comparison,
@strapi/strapi shows a higher growth in the last 2 years.
Note: Some of the Strapi trend above could be folks moving from the old
strapi (3.x) package to the new
@strapi/strapi (4.x) package but despite that, the absolute numbers suggest a wider Strapi adoption.
When comparing Directus and Strapi features, there is no clear winner. One is better than the other at certain features. As a result, identifying our
must have features can help us drive our choice. For example -
“We have an existing database (or backend setup) and we seek to have an Rest APIs / GraphQL / Admin UI for our data.” - pick Directus.
“We absolutely need content versioning.” - pick Directus.
“We have a large Admin UI team across departments and need a fine grained access control for our Admin UI screens and features.” - pick Strapi.
“We don’t know what all we may need but we feel safer adopting something more popular.” - pick Strapi.
Back in 2017, I started working as an independent web performance specialist for React frontends. Over the years, a few of the teams where I worked for long were kind enough to let me help solve their CMS issues.
Fast forward to now, I have worked with multiple teams to choose the right CMS framework and then setup + implement the chosen solution.
To discuss your CMS specific pain points, email me at firstname.lastname@example.org.