Basic workflow

Overview

The basic workflow for Val is to: define your content schema, register your modules, and use the content in your app. This guide will walk you through creating your first Val content module.

Step 1: Create a Val module

Content in Val is defined in .val.ts files. These files contain both the schema (what fields your content has) and the initial content values.

If you used the initialization script, you should already have example files. Otherwise, create your first module:

app/page.val.ts

// app/page.val.ts
import { s, c } from "@/val.config";

// Define your content schema
const schema = s.object({
  text: s.string(),
});

// Create the module with a unique path, schema, and initial content
export default c.define("/app/page.val.ts", schema, {
  text: "My first Val content",
});

Understanding the code

  • s is the schema builder - it provides type-safe schema definitions

  • c is the content builder - used to define and validate content modules

  • c.define() takes three arguments: a unique path identifier, the schema, and the initial content

  • The content object must match the schema - TypeScript will catch any mismatches

Step 2: Register your module

After creating a Val module, you need to register it in val.modules.ts so Val knows about it. This file should be at the root of your project.

val.modules.ts

import { modules } from "@valbuild/next";
import { config } from "./val.config";

export default modules(config, [
  // Add your module here
  { def: () => import("./app/page.val") },
  // You can add more modules as your project grows
]);

The def property uses a function that dynamically imports your module. This enables code splitting and better performance.

Step 3: Use content in your app

Now you can use your Val content in React components. Val provides different APIs depending on whether you're using Client or Server Components.

Client Components

For client-side rendering, use the useVal hook. This is perfect for interactive components that need client-side state.

app/page.tsx (Client Component)

"use client";
import { useVal } from "@/val/val.client";
import pageVal from "./page.val";

export default function Page() {
  // useVal returns the content from your Val module
  const { text } = useVal(pageVal);
  
  return (
    <div>
      <h1>{text}</h1>
    </div>
  );
}

Server Components

For server-side rendering (recommended for better performance), use the fetchVal function. This renders on the server and sends HTML to the client.

app/page.tsx (Server Component)

import { fetchVal } from "@/val/val.rsc";
import pageVal from "./page.val";

export default async function Page() {
  // fetchVal is async and fetches content server-side
  const { text } = await fetchVal(pageVal);
  
  return (
    <div>
      <h1>{text}</h1>
    </div>
  );
}

Editing your content

Once your Val module is set up and registered, you can edit the content in two ways:

  1. Directly in code - Edit the default export in your .val.ts file

  2. Using Val Studio - Visit /val in your browser for a visual editing interface (requires running your dev server)

Val Studio provides a user-friendly interface where non-technical team members can edit content without touching code.

Next steps

Now that you have your first Val module working, you can:

Common issues

Module not found: Make sure your module is registered in val.modules.ts and the import path is correct.

Type errors: Your content object must match the schema exactly. Check that all required fields are present and have the correct types.

Content not updating: In development, you may need to refresh the page or restart your dev server after making changes to .val.ts files.