Skip to main content
On this page

    Understanding the Hooks System - Dynamic Data Without the Complexity

    Aris Ripandi Updated vitto hooks data tutorial

    Vitto's hooks system lets you pull data from anywhere without a heavy data layer. Here's how to use it effectively.

    One of Vitto’s defining features is its hooks system — a simple but powerful way to inject dynamic data into your static templates.

    The Problem

    Static sites are great for performance, but they often struggle with dynamic content. Traditional solutions include:

    • Client-side fetching (slow, bad for SEO)
    • Build-time data scripts (fragile, hard to maintain)
    • External CMS (complex, costly)

    The Hook Solution

    Vitto hooks are async functions that run at build time. They fetch or generate data and make it available to your templates:

    ts
    // hooks/posts.ts
    import { defineHooks } from 'vitto';
    import fs from 'node:fs/promises';
    import path from 'node:path';
    
    export default defineHooks('posts', async () => {
      const dir = path.join(process.cwd(), 'content/posts');
      const files = await fs.readdir(dir);
      const posts = await Promise.all(
        files.map(async (file) => {
          const content = await fs.readFile(path.join(dir, file), 'utf-8');
          return { slug: file.replace('.md', ''), content };
        })
      );
      return posts;
    });

    Using Data in Templates

    Register the hook in vite.config.ts:

    ts
    vitto({
      hooks: {
        posts: postsHook,
      },
    });

    Then access the data in any template:

    html
    {{ for post of posts }}
      <article>
        <h2>{{ post.title }}</h2>
        <a href="/blog/{{ post.slug }}">Read more</a>
      </article>
    {{ /for }}

    Hook Types

    Type Use Case Example
    Static Fixed data Navigation menu, site config
    Async API calls, file reads Blog posts, product listings
    Parameterized Filtered queries Single post, search results

    Best Practices

    Warning

    Hooks run at every build. For data that rarely changes, consider caching or writing it directly to a JSON file.