Content API

Content API

The content API in Val provides helpers for defining content in your .val.ts files. The c object exported from your val.config contains c.define() and c.json(). Images and files are not constructed with a helper: they are plain objects carrying a path, described below.

c.define

The c.define() function is used to export content from Val module files. It takes three parameters: the module path, the schema, and the content data.

Signature

c.define(modulePath, schema, content)

Parameters

  • modulePath - The file path of the module, relative to the project root (e.g., /app/(main)/page.val.ts)

  • schema - The schema definition, see schema types

  • content - The actual content data that matches the schema

Basic example

Here's a simple example of using c.define() to export page content:

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

const schema = s.object({
  title: s.string(),
  description: s.string(),
  published: s.boolean(),
});

export default c.define("/app/blog/page.val.ts", schema, {
  title: "My First Blog Post",
  description: "This is a great introduction to Val",
  published: true,
});

Images

An image is a plain object with a path and the metadata read off the file. There is no constructor to call - the same object can be written in a .val.ts and in a .val.json entry. Local images must be stored in the /public/val folder.

For schema definition, see the s.image() documentation.

Signature

type ImageSource = {
  path: string;
  width?: number;
  height?: number;
  mimeType?: string;
  alt?: string;
  hotspot?: { x: number; y: number };
}

Parameters

  • path - The file path to the image, relative to the project root (must be in /public/val), or the URL of a remote image

  • The remaining fields are generated using the VS Code extension, the CLI or the UI:

    • width - The width of the image in pixels

    • height - The height of the image in pixels

    • mimeType - The MIME type of the image (e.g., image/jpeg, image/png)

    • alt and hotspot are yours to set - alt is the alt text, hotspot is the point that must stay in frame when the image is cropped

Example

Here's how to define an image in a Val module:

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

const schema = s.object({
  title: s.string(),
  hero: s.image(),
});

export default c.define("/content/page.val.ts", schema, {
  title: "Welcome",
  hero: {
    path: "/public/val/hero.jpg",
    width: 1920,
    height: 1080,
    mimeType: "image/jpeg",
  },
});

Important notes

  • All images must be stored in the /public/val folder

  • Use CLI or the VS Code extension to generate metadata

  • The width and height should match the actual dimensions of the image

  • The MIME type should accurately reflect the image format

Files

Generic files (such as videos, PDFs, or other documents) are plain objects too, carrying a path and a mimeType. Like images, local files must be stored in the public/val folder.

For schema definition, see the s.file() documentation.

Signature

type FileSource = {
  path: string;
  mimeType?: string;
}

Parameters

  • path - The file path to the file, relative to the project root (must be in /public/val), or the URL of a remote file

  • mimeType - typically generated using the VS Code extension, the CLI or the UI:

    • mimeType: the mime type of the file

Example with video

Here's how to define a video file:

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

const schema = s.object({
  title: s.string(),
  video: s.file({ accept: "video/*" }),
});

export default c.define("/content/video.val.ts", schema, {
  title: "Product Demo",
  video: { path: "/public/val/demo.mp4", mimeType: "video/mp4" },
});

Important notes

  • All files must be stored in the /public/val folder

  • The accept parameter in s.file() should match the MIME type of the file

  • You can use wildcards like video/* to accept multiple file types

Remote files

Remote files and images are stored on Val's remote server instead of in your Git repository. They are written exactly like local ones - remote-ness is read off the path: anything that is not under /public is remote. Remote files are immutable and managed by Val Build.

For detailed information on setting up and using remote files, see the Remote Files guide.

Signature

{
  path: "https://remote.val.build/file/...",
  mimeType: "image/jpeg",
}

Parameters

  • path - The remote URL to the file on Val's server

  • The metadata about the remote file is written alongside it, the same as for a local file:

    • mimeType - The MIME type of the file (e.g., image/jpeg, video/mp4)

Example with remote image

Here's how to define a remote image. Note that the schema must include .remote() to enable remote files:

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

const schema = s.object({
  hero: s.image().remote(),
});

export default c.define("/content/page.val.ts", schema, {
  hero: {
    path: "https://remote.val.build/file/p/ce803e0/b/v08/v/0.84.1/h/637c/f/c89d27d4be02/p/public/val/hero.jpg",
    mimeType: "image/jpeg",
    width: 1920,
    height: 1080,
    alt: "Hero image",
  },
});

Example with remote video

const schema = s.object({
  video: s.file({ accept: "video/*" }).remote(),
});

export default c.define("/content/video.val.ts", schema, {
  video: {
    path: "https://remote.val.build/file/p/.../video.mp4",
    mimeType: "video/mp4",
  },
});

Important notes

  • You must add .remote() to your schema before pointing a field at a remote URL

  • Remote files require connecting your project to Val Build

  • Remote file URLs are automatically generated when you upload files using the CLI or VS Code extension

  • You should not manually create remote URLs - use the Val tools to upload files

See Also

For complete setup instructions, uploading workflows, and best practices, see the Remote Files documentation.