Videos

Working with Videos

Videos in Val

Videos in Val are handled using the s.file() schema with accept: 'video/*'. This provides type-safe video handling with support for local and remote videos.

Defining Video Schema

Use s.file({ accept: 'video/*' }) to define a video field. Val Studio will automatically render it with a video preview:

const pageSchema = s.object({
  heroVideo: s.file({ accept: "video/*" }),
  tutorialVideo: s.file({ accept: "video/*" }).nullable(),
});

Adding Video Content

Videos must be stored in the /public/val folder. Use c.file() to reference them with proper metadata:

export default c.define("/content/page.val.ts", pageSchema, {
  heroVideo: c.file("/public/val/hero.mp4", {
    mimeType: "video/mp4"
  }),
  tutorialVideo: c.file("/public/val/tutorial.webm", {
    mimeType: "video/webm"
  }),
});

Rendering Videos

Access the video URL using the .url property and render it with standard HTML5 video elements:

Basic video rendering

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

export default async function Page() {
  const { heroVideo } = await fetchVal(pageVal);
  
  return (
    <video 
      src={heroVideo.url} 
      controls 
      className="w-full"
    >
      Your browser does not support the video tag.
    </video>
  );
}

Advanced Video Controls

For more control over video playback, you can add additional HTML5 video attributes:

Video with autoplay and loop

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

export default async function Page() {
  const { heroVideo } = await fetchVal(pageVal);
  
  return (
    <video
      controls
      autoPlay
      muted
      loop
      playsInline
      className="w-full"
      preload="metadata"
      {...val.attrs(heroVideo.url)}
    >
      <source src={val.raw(heroVideo.url)} type="video/mp4" />
      Your browser does not support the video tag.
    </video>
  );
}

Video Attributes Explained

Common video attributes:

  • controls - Shows play, pause, and volume controls

  • autoPlay - Starts playing automatically (usually requires muted)

  • muted - Mutes the video (required for autoplay on most browsers)

  • loop - Restarts the video when it ends

  • playsInline - Plays inline on mobile devices instead of fullscreen

  • preload='metadata' - Loads only video metadata to save bandwidth

Remote Videos

For large video files, you can use remote storage. Enable remote videos by adding .remote() to your schema. See the Remote Files guide for details on setup and uploading.

Remote video example

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

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

NOTE: Future Streaming Support

Val currently serves videos as regular file downloads. Support for optimized video streaming and adaptive bitrate streaming may be added in a future release for better performance and user experience.