Content as Code

Val is a NextJS native, local-first, fully type-safe CMS where content is stored as code

npm create @valbuild

We wanted a CMS that feels small and scales well

Fredrik Ekholdt, CMS enthusiast and creator of Val

Suckless

The Ultimate Developer Experience

Val is a reaction to CMS that feels like an overkill in every situation. We wanted to create something that both feels small and easy to get started with, but also works for large teams.

Content As Code

In Val you store the content as code. This enables true end-to-end typesafety, refactorable content and tooling unlike any other CMS.

/* This is a .val.ts file. */
const schema = s.object({
  // Schema types are based on JSON and TypeScript built-in types.
  message: s.string(),
});

// What makes Val special is that content is defined here (in code):
export default c.define("/app/(main)/page.val.ts", schema, {
  message: "I wrote this in my editor, but I can change it using the UI too!",
});

True Typesafety

When Content is Code, the actual content can be as type-safe as the rest of your app. This does not only mean that you can know that the content can render correctly, you can also quickly understand the shape of your content, without needing extra tooling. You also avoid generated types with all this entails: updates when you fogot to do it, custom github actions to run and verify generated types automatically and, last but not least: ugly-ass types.

True Typesafety

Refactorable Content

It is hard to find the perfect way of structuring your code and your content, but with Val it's at least easy to refactor when you know you made a mistake.

Refactorable Content

A CMS with a LSP

The ultimate developer experience must have awesome tools!

Vals VS Code extension (which hosts the LSP) and ESlint plugin provides you with instant feedback right in your code.

A CMS with a LSP

Git based

Since your content is code, testing out things locally, creating branches or even preview-branches on Vercel works just as you'd expect.

Git based

What you don't do, determines what you can do.

Tim Ferris

Delibirate omissions

Less, But Better

Val is designed to be easy to pick up and have a minimum amount of things to learn. That's why we have delibrately omitted the following things:

No Query Language

Less to learn

Val does not need any query language since data is built as part of your application. Simple is an overused term these, days, but there's no other way to put it: it is just simpler not to learn (or force your future colleagues) a query language to fetch content.

No Database

Less to manage

As much as we like databases, requiring one to be able to let editors change an application is neither simple nor easy.

Val runs on its own. Even locally. Without an internet connection.

No Separate Runtime

Less to run

Content is bundled as part of your code. This means that your page will be up and running even if Val goes down. It also means that it will be able to serve requests as quick as you hosting provider lets you, since there's no fetching required (since you content is literally built with your app).

No Abstraction Model

Less to understand

Val does not have its own abstraction model, instead we use JSON and Typescript to build our schemas: a string is a string, an array is an array. Rich text is not a custom format, it is represented using semantic HTML 5. Even Vals internal patches is based on standards (RFC 6902).