A barebones SvelteKit starter template for building a blog powered by Sanity CMS and styled with daisyUI.
Just a heads-up: this template includes Tailwind CSS and daisyUI, but they haven't really been used much yet. So feel free to have fun customizing and giving your site a complete makeover from the ground up!
To get up and running with this template, you should be familiar with SvelteKit. If you're new to it, the official documentation is a great place to start:
Once you're comfortable, clone this template and customize it to fit your needs.
Look for TODO:
comments throughout the codebase to identify areas that need your attention. Below are the key files and folders you’ll likely want to update:
src/lib/index.ts
– Basic site information (e.g., title, description, author).src/lib/components/MetaHome.svelte
– Metadata configuration for your home page.static/
– Your site's favicon and other identity-defining images..env
– Environment variables (e.g., API keys, project IDs).Here's a finished website made with this template to give you some inspiration for your own site makeover.
Install a dependencies
npm i easymde sanity-plugin-markdown
A sample of post schema
// schemaTypes/postType.ts
import { defineField, defineType } from 'sanity'
export const postType = defineType({
name: 'post',
title: 'Post',
type: 'document',
fields: [
defineField({
name: 'title',
type: 'string',
validation: (rule) => rule.required(),
}),
defineField({
name: 'slug',
type: 'slug',
options: { source: 'title' },
validation: (rule) => rule.required(),
}),
defineField({
name: 'publishedAt',
type: 'datetime',
initialValue: () => new Date().toISOString(),
validation: (rule) => rule.required(),
}),
defineField({
name: 'image',
type: 'image',
}),
defineField({
name: 'video',
type: 'file',
}),
defineField({
name: 'excerpt',
type: 'string',
}),
defineField({
name: 'tags',
type: 'array',
of: [{ type: 'string' }]
}),
defineField({
name: 'categories',
type: 'array',
of: [{ type: 'string' }]
}),
defineField({
name: 'draft',
type: 'boolean',
initialValue: false
}),
defineField({
name: 'readingTime',
type: 'number',
}),
defineField({
name: 'body',
type: 'markdown',
}),
],
})
*[_type == 'post' && !draft] | order(_id)[0...5] {
_id,
title,
"slug": slug.current,
publishedAt,
"imageUrl": image.asset->url,
excerpt,
tags,
categories,
draft,
readingTime,
body,
headings,
"videoUrl": video.asset->url
}
*[_type == 'post' && slug.current == $slug] | order(_id)[0...1] {
_id,
title,
"slug": slug.current,
publishedAt,
"imageUrl": image.asset->url,
excerpt,
tags,
categories,
draft,
readingTime,
body,
headings,
"videoUrl": video.asset->url
}
*[_type == 'post' && !draft && $tagged in tags] | order(_id)[0...5] {
_id,
title,
"slug": slug.current,
publishedAt,
"imageUrl": image.asset->url,
excerpt,
tags,
categories,
draft,
readingTime,
body,
headings,
"videoUrl": video.asset->url
}
💡 Tips:
- Replace
0...5
with dynamic values for pagination.- Always use
"slug": slug.current
to avoid nested objects in your output.
# Paginated posts
https://9fp52ven.api.sanity.io/v2025-05-02/data/query/production?query=*%5B_type+%3D%3D+%27post%27+%26%26+%21draft%5D+%7C+order%28_id%29%5B0...5%5D+%7B%0A++_id%2C%0A++title%2C%0A++%22slug%22%3A+slug.current%2C%0A++publishedAt%2C%0A++%22imageUrl%22%3A+image.asset-%3Eurl%2C%0A++excerpt%2C%0A++tags%2C%0A++categories%2C%0A++draft%2C%0A++readingTime%2C%0A++body%2C%0A++headings%2C%0A++%22videoUrl%22%3A+video.asset-%3Eurl%0A%7D%0A&perspective=drafts
# Post by slug
https://9fp52ven.api.sanity.io/v2025-05-02/data/query/production?query=*%5B_type+%3D%3D+%27post%27+%26%26+slug.current+%3D%3D+%24slug%5D+%7C+order%28_id%29%5B0...1%5D+%7B%0A++_id%2C%0A++title%2C%0A++%22slug%22%3A+slug.current%2C%0A++publishedAt%2C%0A++%22imageUrl%22%3A+image.asset-%3Eurl%2C%0A++excerpt%2C%0A++tags%2C%0A++categories%2C%0A++draft%2C%0A++readingTime%2C%0A++body%2C%0A++headings%2C%0A++%22videoUrl%22%3A+video.asset-%3Eurl%0A%7D%0A&%24slug=%22less-code-with-riverpod%22&perspective=drafts
# Tags
https://9fp52ven.api.sanity.io/v2025-05-02/data/query/production?query=*%5B_type+%3D%3D+%27post%27+%26%26+%21draft+%26%26+%24tagged+in+tags%5D+%7C+order%28_id%29%5B0...5%5D+%7B%0A++_id%2C%0A++title%2C%0A++%22slug%22%3A+slug.current%2C%0A++publishedAt%2C%0A++%22imageUrl%22%3A+image.asset-%3Eurl%2C%0A++excerpt%2C%0A++tags%2C%0A++categories%2C%0A++draft%2C%0A++readingTime%2C%0A++body%2C%0A++headings%2C%0A++%22videoUrl%22%3A+video.asset-%3Eurl%0A%7D&%24tagged=%22terminal%22&perspective=drafts