Svelte blog

How to Build a Blog in Svelte With a Headless CMS

Posted on April 7th, 2023 by Antonello Zanini

A headless CMS is an excellent choice for creating a fast, flexible, easy-to-manage Svelte blog. By decoupling content management from presentation, a headless CMS offers excellent flexibility and scalability regarding content distribution. In this tutorial, you will learn how to build a blog with SvelteKit and a headless CMS.

Let’s dive in! 

What Is SvelteKit?

Svelte is a popular component framework and language used to build user interfaces for web applications. What makes Svelte different from libraries such as React is that it does not rely on a virtual DOM. Instead, Svelte compiles HTML templates at build time into specialized code that directly manipulates the DOM. This means there is no virtual DOM overhead at runtime. Also, that approach reduces the size of the files the server has to send to the client. For this reason, Svelte is a fast and efficient language.

If you are wondering about the difference between Svelte and SvelteKit, the answer is simple! Svelte is a language, while SvelteKit is a framework built on top of Svelte that allows you to build server-side rendered, high-performance, SEO-oriented web applications. Note that SvelteKit comes with native TypeScript support, which makes it easy to avoid errors early and improve code quality.

Jump into how to use SvelteKit to create a blog with a headless CMS. But first, understand why you really need a headless CMS. 

Why a Headless CMS?

A headless CMS is a backend-only SaaS (Software as a Service) platform that enables the same content to be distributed across different frontends via API, acting as a single source of truth. In other words, a headless CMS stores the content on a centralized database, exposes APIs for content management and distribution, and comes with an easy-to-use user interface for editing content. 

In particular, there are at least three good reasons why a headless CMS is good for building a blog:

  • Flexible content management: Since the CMS is decoupled from the presentation layer, you can use any front-end technology you want to build your blog. This gives you more flexibility in terms of how to structure and present your content.

  • Seamless integrations: A headless CMS is generally part of a composable architecture, where you can easily integrate other tools, services, and technologies. 

  • Scalability: A CMS with no head can help your blog scale as it grows in popularity. You do not have to worry about running into performance issues or scaling the system. The SaaS provider will take care of that for you.


A complete headless CMS such as DatoCMS also offers SEO optimization, image management, and internationalization capabilities for free. Let’s now learn how to build a blog in Svelte and DatoCMS! 

Create a Svelte Blog With a Headless CMS and SvelteKit

Follow this step-by-step tutorial and create a blog that uses SvelteKit as the front-end technology and relies on a headless CMS for content management. Take a look at the code of the Svelte blog you are about to build by cloning the GitHub repository that supports this article:

git clone https://github.com/Tonel/svelte-datocms-blog


Buckle up! Time to find out how to integrate DatoCMS into a Svelte app to craft the blog of your dreams!

Set up a SvelteKit project 

First, you need to initialize a project in Svelte. Use the official tool to set up a SvelteKit project called my-svelte-blog with:

npm create svelte@latest my-svelte-blog

During the initialization process, you will be asked some questions. Answer as follows:

┌ Welcome to SvelteKit!
◇ Which Svelte app template?
│ Skeleton project
◇ Add type checking with TypeScript?
│ No
◇ Select additional options (use arrow keys/space bar)
│ none
└ Your project is ready!


Enter the project folder, install the project’s dependencies, and launch your app to verify that it works with:

cd my-svelte-blog
npm install
npm run dev

Open the http://localhost:5173 URL in your browser.  You should now be seeing the SvelteKit welcome page below:

The SvelteKit init default page

Your new SvelteKit app is ready!

Configure a DatoCMS project for your Svelte blog

If you are not yet a DatoCMS account yet, sign-up for free. To create a DatoCMS account, fill out the form below on the registration page:

The DatoCMS sign-up form

The DatoCMS sign-up form: follow the instructions, login in, and you should now get access to the following DatoCMS dashboard:

The DatoCMS project dashboard

The DatoCMS project dashboard: click “New Project,” and then on the “Blank project” option:

Selecting the “Blank project” option

That will open a modal. Name your project, such as “My Svelte Blog,” and click the “Create project” button.

The project creation modal in DatoCMS

As soon as the project creation process ends, the modal window will close, and you will be redirected to the DatoCMS dashboard. In the project table, you will see the newly created project. Select it and click "Enter Project" to access it. 

You are now in the "My Svelte Blog” DatoCMS project. As in any other CMS, the first thing to do is to define the content structure you want to manage. If you are not familiar with this concept, take a look at our documentation page on content modelling

Click the “Models” voice, then the “+” button, and create an “Article” model as below:

Defining the “Article” model

Click the “Save model” button to define the “Article” model. Next, reach the “Article” model page and click on the “Add new field” button to add some fields. Follow the documents to find out more about how DatoCMS handles data fields.

As you can imagine, a basic “Article” model requires at least a title, a slug, and a structured-text field for the content:

The fields the “Article” model consists of

Keep in mind that this is just a simple example. In a real-world scenario, you will have to define other models to deal with authors, tags, and more. Also, you will need new fields for SEO and manage the relationships between models. Explaining how to do that is not the main goal of this article, but do not worry! The intuitive user interface offered by DatoCMS will guide you through that.

Now, you can populate your blog with some posts! Click the "Content" top menu voice to reach the content management dashboard. Here, click on the “Article” menu on the left to access the following page:

The content management page for the “Article” model

Click “New record” and create the first article of your blog:

Creating a sample blog post

Note that the input elements you can access on this page correspond to the fields defined earlier in the "Article" template. This is how content modelling works!

Fill in these inputs as desired and click "Save" to create your first blog post. Take your time to create a few articles for your blog. Five will be enough. If you want to speed-run this process, use a Lorem Ipsum generator to produce some sample articles. 

Now, look at how to integrate DatoCMS into your SvelteKit app and start retrieving your content via API.

Integrate DatoCMS into your SvelteKit app

Here you will find out how to connect your SvelteKit blog to DatoCMS. For references, read our official guide on how to integrate DatoCMS with Svelte.  

First, you need to install the DatoCMS Svelte client. Add @datocms/svelte to your project’s dependencies with:

npm install @datocms/svelte

This package includes components and utilities to work faster with DatoCMS in Svelte projects. In detail, it makes it easy to interact with the DatoCMS Content Delivery API.

Since most Svelte blog pages will rely on content retrieved from DatoCMS, you should define a utility function that uses fetch() to call a GraphQL API from DatoCMS. Create a lib/utils folder inside src and define a query.js file as below:

import { PUBLIC_DATOCMS_READ_ONLY_API_TOKEN } from '$env/static/public'
export async function performGraphqlQuery({query, variables = {}}) {
// perform the GraphQL request to the
// DatoCMS Content Delivery API
const response = await fetch('https://graphql.datocms.com', {
method: 'POST',
headers: {
Authorization: `Bearer ${PUBLIC_DATOCMS_READ_ONLY_API_TOKEN}`,
},
body: JSON.stringify({
query,
variables,
}),
})
return await response.json()
}

This function makes an authenticated GraphQL request to DatoCMS. To authenticate, you need to put the read-only DatoCMS API token associated with the project in the HTTP Authorization header.

To retrieve that API token, open the “My Svelte Blog” project in DatoCMS and reach the "Settings" dashboard by clicking on the corresponding top menu item. Next, click the "API Token" menu voice on the left, select "Read-only API Token" and click on the "Copy" button.

Retrieving the DatoCMS read-only API token

Retrieving the read-only DatoCMS API token: create a .env file in your SvelteKit project and use your read-only API token as below:

PUBLIC_DATOCMS_READ_ONLY_API_TOKEN=<YOUR_DATOCMS_READ_ONLY_API_TOKEN>

Replace <YOUR_DATOCMS_READ_ONLY_API_TOKEN> with the value of the read-only API token of your DatoCMS project. That value will be read through the $env/static/public mechanism in SvelteKit. Otherwise, set a global environment variable in your platform. 

Do not forget that that token only allows you to call read-only APIs. Since you will use it to retrieve data publicly exposed on the blog, you can safely use the token in the front-end.
Perfect! You can now retrieve content from DatoCMS. Time to create a homepage and a page for each blog post.

Add pages to the Svelte blog

By default, the homepage of a SvelteKit app is represented by the routes/+page.svelte file inside src. To show some blog posts on the homepage, you need to define a load() function in the routes/+page.js file as below:

// src/routes/+page.js
import { performGraphqlQuery } from '$lib/utils/query'
export async function load({}) {
// retrieve the articles to show on the homepage
const responseData = await performGraphqlQuery({
query: `
{
allArticles {
id
title
slug
publicationDate: _firstPublishedAt
}
}
`
})
return responseData.data
}

In SvelteKit, the purpose of the load() function is to retrieve data from an API or database and return it to the page component, enabling server-side rendering (SSR) of SvelteKit pages. So, when a user navigates to a page, the SvelteKit server executes the load() function associated with that page, retrieving the data required to render the page on the server. Next, the SvelteKit server renders the page and returns it to the client.

In this case, the load() function makes a GraphQL query to retrieve the last 20 blog post published. Do not forget that DatoCMS APIs are paginated by default. Then, you can use this data in +page.svelte:

<!-- src/routes/+page.svelte -->
<script>
import { StructuredText } from '@datocms/svelte';
import { error } from '@sveltejs/kit';
export let data;
const { article } = data;
if (!article) {
throw error(404, { message: 'Article Not found' });
}
</script>
<div class="article">
<h1 class="article-title">
{article.title}
</h1>
{#if article.publicationDate}
<div class="article-publication-date">
Article published on: {new Date(article.publicationDate).toLocaleString()}
</div>
{/if}
<div>
<StructuredText data={article.content} />
</div>
</div>

This page presents the articles retrieved in the load() function in clickable cards that take the user to the respective blog post web page blog/<article_slug>. Define that page!

In the routes directory, define a blog/[slug] folder and create the following +page.js file:

// src/routes/blog/[slug]/+page.js
import { performGraphqlQuery } from '$lib/utils/query';
export async function load({ params }) {
// retrieve the articles related to the slug
// specified in the URL
const responseData = await performGraphqlQuery({
query: `
query BlogPostQuery($slug: String!) {
article(filter: { slug: { eq: $slug } }) {
title
slug
publicationDate: _firstPublishedAt
content {
value
blocks
}
}
}
`,
variables: {
// the dynamic "slug" parameter extracted
// from the URL
slug: params.slug
}
});
return responseData.data;
}

The load() function above retrieves the blog post associated with the slug parameter. In particular, [slug] is a dynamic route. In SvelteKit, a dynamic route involves a parameter and can correspond to multiple URLs. In this case, the parameter is the string slug.

Let’s better understand how this mechanism works in an example. Suppose a user visits the /blog/lorem-ipsum-1 page of your blog. In this case, the variable params.slug will contain the string lorem-ipsum-1. That string will then be used in the load() function to run a Graphql query to the DatoCMS Content Delivery API and get the content of the specific article.

Next, you can display the rich-text content returned by the selected article through the <StructuredText> Svelte component from the @datocms/svelte library. Create a +page.svelte file and use that tool as follows:

<!-- src/routes/blog/[slug]/+page.svelte -->
<script>
import { StructuredText } from '@datocms/svelte';
import { error } from '@sveltejs/kit';
export let data;
const { article } = data;
if (!article) {
throw error(404, { message: 'Article Not found' });
}
</script>
<div class="article">
<h1 class="article-title">
{article.title}
</h1>
{#if article.publicationDate}
<div class="article-publication-date">
Article published on: {new Date(article.publicationDate).toLocaleString()}
</div>
{/if}
<div class="article-content">
<StructuredText data={article.content} />
</div>
</div>

In other terms, a dynamic path allows you to consistently display any blog post with a single SvelteKit page component.

The SvelteKit blog now has a homepage showing the latest posts and a single page for each article. If you run the project, you will notice that the user interface of the blog is rather essential. Let's make the blog cooler!

Style your Svelte blog

All pages in a SvelteKit project can share the same layout. If you want to define one, create a +layout.svelte file in the routes directory:

<!-- src/routes/+layout.svelte -->
<div class="header">
<a href="/">My Svelte Blog</a>
</div>
<div class="container">
<slot />
</div>
<style>
@import url("https://fonts.googleapis.com/css2?family=Inter&display=swap");
* {
font-family: "Inter", Helvetica, Arial,serif;
}
.header {
color: white;
background-color: #696969;
padding: 30px;
margin-bottom: 30px;
border-radius: 10px;
}
.header a {
all: unset;
font-size: 28px;
}
.header a:hover {
text-decoration: underline;
cursor: pointer;
}
.container {
width: 100%;
max-width: 1140px;
margin-right: auto;
margin-left: auto;
padding-right: 15px;
padding-left: 15px;
}
@media (min-width: 768px) {
.container {
max-width: 720px;
}
}
@media (min-width: 992px) {
.container {
max-width: 960px;
}
}
@media (min-width: 1200px) {
.container {
max-width: 1140px;
}
}
</style>

Note that a Svelte template file must have a <slot>. This placeholder HTML element will be replaced by the top-level component defined in the .svelte page files. 

As the example above shows, styling a Svelte component locally is easy. You can assign CSS classes to your HTML elements and define some CSS rules in the <style> tag.
Using the same approach, you can style the homepage by adding the following lines to src/routes/+page.svelte:

<!-- src/routes/+page.svelte -->
<!-- ... -->
<style>
.title h1 {
font-size: 35px;
text-align: center;
margin-bottom: 20px;
}
.articles a {
all: unset;
}
.articles a:hover {
cursor: pointer;
}
.articles .article-card {
border-radius: 10px;
border: solid 1px #696969;
padding: 25px 15px;
margin-bottom: 10px;
}
.articles a:hover .article-card {
border: solid 1px #FF7751;
}
.articles a:hover .article-title {
color: #FF7751;
}
.articles .article-card .article-title {
font-size: 22px;
margin-bottom: 10px;
}
.articles .article-card .article-publication-date {
color: #696969;
font-size: 14px;
}
</style>
<!-- ... -->

Similarly, style the blog post dynamic page:

<!-- src/routes/blog/[slug]/+page.svelte -->
<!-- ... -->
<style>
.article h1 {
font-size: 55px;
margin-bottom: 12px;
}
.article .article-publication-date {
color: #696969;
font-size: 16px;
margin-bottom: 44px;
}
.article .article-content {
font-size: 18px;
line-height: 30px;
}
</style>
<!-- ... -->

Fantastic! Your blog in Svelte will now look much better! Time to see it in action!

Test the SvelteKit blog

Open the terminal in the root directory of your project. Type the command below to start your SvelteKit blog:

npm run dev

Here is what the homepage of your blog will now look like:

The homepage

When clicking on an article card on the homepage, the user will then be redirected to the following article page below:

Article page

Et voilà! You just saw how to build a blog with Svelte and DatoCMS as headless CMS! The tutorial ends here, but there is still much more to do and explore. For example, you could encapsulate the code in some Svelte components, add pagination logic to the home, and use the DatoCMS component for image rendering. Keep improving your Svelte blog!

Create a Blog in 2 Minutes With the DatoCMS SvelteKit Blog Starter 

By now, you know what it takes to create a blog using SvelteKit and a headless CMS like DatoCMS. Though that is not challenging, it does require multiple steps and a significant investment of time. Luckily, if you want to speed up building a feature-rich blog in Svelte, DatoCMS has the perfect solution for you!

Instantly create a blog based on SvelteKit through the DatoCMS Svelte blog template. With just one click, you will gain access to:

  • A full set-configured DatoCMS project to manage your blog’s content

  • A GitHub repository built on the template codebase that contains your code

  • Deployment of your blog to Vercel or Netlify


Check out the template preview page to inspect what your SvelteKit blog will look like. You are just one click away from achieving that result!

Click on the button below to get started! 

SvelteKit Blog
SvelteKit Blog
Publish this demo online with just three clicks in a matter of minutes.
Deploy the demo project

Follow the step-by-step procedure and set up your SvelteKit blog!

Conclusion

In this article, you saw SvelteKit and why using it with a headless CMS is the winning formula for building a powerful blog. Then, you learned how to create a blog with Svelte and DatoCMS in a step-by-step tutorial. As shown here, DatoCMS is a powerful Svelte CMS that perfectly integrates with SvelteKit.

Thanks for reading! We hope that you found this article helpful. Feel free to reach out to us on Twitter with any questions, comments, or suggestions.