logoContent Collections

Quickstart SvelteKit

Integrate Content Collections into your SvelteKit app

Install required packages:

We have to install the following packages:

  • @content-collections/core
  • @content-collections/vite
  • zod
npm i @content-collections/core @content-collections/vite zod -D

Adjust your svelte.config.js:

const config = {
  // ...
  kit: {
    // ...
    alias: {
      "content-collections": "./.content-collections/generated",
    },
  },
};

We require a path alias for the generated files. This is necessary because we will generate the files in the .content-collections/generated folder.

Modify your vite.config.ts:

import { sveltekit } from "@sveltejs/kit/vite";
import contentCollections from "@content-collections/vite";
import { defineConfig } from "vite";
 
export default defineConfig({
  plugins: [sveltekit(), contentCollections()],
});

Add the Content Collections plugin to your Vite config. For more details on the vite adapter, refer to the documentation.

Add the new .content-collections directory to your project's .gitignore file — the files in this directory are always regenerated and can be safely ignored by Git.

.content-collections

Create a content-collections.ts file at the root of your project:

import { defineCollection, defineConfig } from "@content-collections/core";
import { z } from "zod";
 
const posts = defineCollection({
  name: "posts",
  directory: "src/posts",
  include: "**/*.md",
  schema: z.object({
    title: z.string(),
    summary: z.string(),
  }),
  transform: (doc) => ({
    ...doc,
    slug: doc.title.toLowerCase().replace(/ /g, '-'),
  }),
});
 
export default defineConfig({
  collections: [posts],
});

This file defines a collection named posts in the src/posts folder. The collection will include all markdown files (**/*.md) and the schema will validate the title and summary fields.

For more information about the configuration have a look at the documentation.

Create your content files (e.g.: src/posts/hello-world.md):

---
title: "Hello world"
summary: "This is my first post!"
---
 
# Hello world
 
This is my first post!
... rest of the markdown content

You can create unlimited content files. These files will be validated against the schema defined in the content-collections.ts file. If the files are valid, they will be automatically added to the posts collection.

Example with Svelte 5 and SvelteKit

Showing Document List (Posts)

To generate a list of posts create in a src/posts directory two files.

+page.ts file

import type { PageLoad } from './$types';
import { allPosts } from 'content-collections';
 
export const load: PageLoad = async () => {
  // Fetch all posts from the content collection and filter or sort (optional)
  let posts = allPosts;
 
  return {
    posts,
  };
};

+page.svelte file

<script lang="ts">
  import type { PageProps } from './$types';
 
  let { data }: PageProps = $props();
</script>
 
<h1>Posts</h1>
<ul>
  {#each data.posts as post}
    <li>
      <h2>{post.title}</h2>
      <p>{post.summary}</p>
    </li>
  {/each}
</ul>

Now you can just import the allPosts collection and use it in your code. The allPosts collection will contain all posts that are valid. The post object will contain the slug, title, summary and content fields as well as some meta information in the _meta field.

Showing Document Entry (Post)

For showing a single post create two files in src/posts/[...slug].

+page.ts file

import type { PageLoad } from './$types';
import { error } from '@sveltejs/kit';
import { allPosts } from 'content-collections';
 
export const load: PageLoad = async ({ params }) => {
  const post = allPosts.find((post) => post.slug == params.slug);
  if (!post) {
    error(404, `Could not find ${params.slug}`);
  }
 
  return {
    post,
  };
};

+page.svelte file

<script lang="ts">
  import type { PageProps } from './$types';
 
  let { data }: PageProps = $props();
 
  const post = $derived(data.post);
</script>
 
<h1>{post.title}</h1>

On this page