Using Silverstripe as “headless”

“Headless” is a word that has been circulating the web for quite some time now, but what does it actually mean? And why and when would you want to go with a headless solution for your website?

"Headless" is a word that has been circulating the web for quite some time now, but what does it actually mean? And why and when would you want to go with a headless solution for your website?

In this post I will try to explain what headless is and when to choose or not to choose that solution, and also provide a simple guide on how you could get started with using Silverstripe as headless by using GraphQL-endpoints to display your data.

headless cms image

Simply put, headless means that you separate the backend and frontend parts of your web-application. By creating an API with endpoints that provides the data from your backend-models, you could have a different server running a web-application with Vue/React rendering that data as a separate frontend. One scenario could be that you would like to have both a website and an application running on both iOS and Android with the same content, then headless would be ideal for you: Having one place to edit your content which will then be displayed in all your channels at once.

So when would headless be a bad idea then? Well, if you are building a basic website with some different pages and a simple contact form, using headless could be a bit overhead. If that website would grow into a popular blog or if you would like to have an app running on iOS or Android as well, there is always the option to add API-endpoints later on. If you are building a frontend based on pure JavaScript, it could also be a problem with SEO, however, there seems to be a divided opinion regarding this, while some people claim Google can see what the browser sees, some people claim they do not.


In this guide, we will create a simple GraphQL-endpoint that will display your data. Note that we will not use the CMS part of Silverstripe, just the framework and admin parts. Start off by creating a new project with the following command in your terminal:

composer create-project silverstripe/recipe-core ss-graphql-guide

the installation could take a few minutes to complete. When the installation is completed, run the following command to add the admin part of silverstripe:

cd ss-graphql-guide and hit enter composer require silverstripe/admin.

Open your newly created project in your favorite IDE and add a .env file to the project root, this will contain your database-information, copy the following into your .env file and replace "xxx" with your information:

Open your project in your favorite browser and add /dev/build at the end of the URL, this will create the necessary tables in your newly created database. Make sure there are no errors when /dev/build has finished loading. Change /dev/build to /admin in your browser and provide the details from your .env(SS_DEFAULT_ADMIN_USERNAME and SS_DEFAULT_ADMIN_PASSWORD) in the form, hit enter and you should see the Silverstripe-admin interface, similar to the following:


There are two vital Silverstripe-modules that we will need for this project, go back to your terminal and type in the following command:

composer require silverstripe/graphql --dev silverstripe/graphql-devtools

when the installation is completed, run another dev/build in your browser. After the dev/build is completed, go towards /dev/graphiql in your browser and you should see the following interface:


This is a UI where we can test our GraphQL-queries to make sure everything works as expected, but first, we need to expose our data to the GraphQL-endpoints, in this guide, we will use a simple DataObject called "BlogPost".

Head back to your editor, inside the /app/ folder of your project, add a new file called BlogPost.php with the following lines of code:

Add another file called BlogPostAdmin.php with the following code:

Run another dev/build and head back to /admin, you should now see a new menu-item called "Blogposts", add a few different dummy-posts, these will be needed for our queries to the endpoint later on.


Now that we have added our new object we will need to add two new files, firstly, add a new file called BlogPostTypeCreator.php and add the following code:

Types describe your data and GraphQL uses this information to validate queries:


Add another file called ReadBlogPostQueryCreator.php and add the following code:

Now that we have added our object, added the type and also exposing it to an endpoint, we need to update our mysite.yml with the following code:

Run another dev/build, when it is completed you can go back to /dev/graphiql and refresh the page. On the left side, add the following snippet:

Hit the play button and you should see a list of your created Blogposts from earlier:


You can also add /graphql/?query={readBlogPost{Title+Content}} in your browser and get the same result:

browser query

As of now, we are just returning all blogposts, with no filters available, lets add the possibility to add a filter by the title and content, where we use the SearchFilter Modifiers available in Silverstripe, in this example we will use the PartialMatchFilter. Update your ReadBlogPostQueryCreator.php by adding a new method called args:

Update your resolve-method to look like this:

With this updates to the files, we can now go back to /dev/graphiql and add the following query:

This will add a filter for the title, looking for any title that contains "Third". Since we have a blogpost with the title "Third Blogpost", this one should be returned:


Replace "Title" with "Content" and "Third" with any other word in your query, if there is a match, one or more blogposts will be returned based on the content instead.

That's it! You should now have a simple GraphQL-endpoint that exposes your content for queries. There is also funtionality for adding mutations, which means that you create data instead of reading it. There will be a guide for that in the future!

Happy coding!

Vad kan vi göra för dig?

Har du en bra idé eller ett problem som du behöver hjälp att lösa?
Ta gärna kontakt med oss för att se vad vi kan göra för er, och hur vi kan hjälpa er!

Contact us