Skip to content

Quick Start

Get a timbl CMS running and queryable from zero. You need Bun installed.

1. Install and run

Terminal window
bun install
bun run dev

The server starts on http://localhost:3000. Open http://localhost:3000/docs for the auto-generated API docs (Scalar UI), or http://localhost:3000/openapi.json for the raw OpenAPI document.

2. Define a schema

Create content.config.ts in your project root. This is where you define your content model.

import { defineCMS, defineCollection, defineGlobal } from "timbl";
export default defineCMS({
collections: [
defineCollection({
key: "posts",
labels: { singular: "Post", plural: "Posts" },
fields: [
{ key: "title", type: "text", required: true },
{ key: "slug", type: "slug", required: true },
{ key: "body", type: "markdown" },
{ key: "status", type: "select", options: ["draft", "published"] },
],
}),
],
globals: [
defineGlobal({
key: "siteSettings",
label: "Site Settings",
fields: [{ key: "siteName", type: "text" }],
}),
],
});

The dev server picks up config changes on restart. See Configuration for the full schema builder API, and Field Types for every field option.

3. Create a user

Writes need a session. Register a user and save the cookie for the next step:

Terminal window
curl -c cookies.txt -X POST http://localhost:3000/api/cms/auth/actions/register \
-H "Content-Type: application/json" \
-d '{"name":"Editor","email":"editor@example.com","password":"correct horse battery staple"}'

4. Create content

Use the saved cookie to authenticate the write:

Terminal window
curl -b cookies.txt -X POST http://localhost:3000/api/posts \
-H "Content-Type: application/json" \
-d '{"title":"Hello","slug":"hello","status":"published","body":"# Hello"}'

5. Query content

Reads are public by default, no cookie needed:

Terminal window
curl http://localhost:3000/api/posts?status=published

You get JSON with collection, total, limit, offset, and items. See the HTTP API Reference for query parameters, filters, and relation expansion.

6. Use the client SDK

For a typed frontend, install @timbl/client and infer types from your config:

import { createTimblClient, type InferCMS } from "@timbl/client";
import type cms from "./content.config";
const client = createTimblClient<InferCMS<typeof cms>>({
baseUrl: "http://localhost:3000",
});
const posts = await client.collection("posts").findMany({ status: "published" });
const post = await client.collection("posts").findBySlug("hello");
const settings = await client.global("siteSettings").get();

The client ships zero runtime dependencies. It consumes your config as a type-only import, so @timbl/core never reaches your frontend bundle. See the Client SDK Reference for the full method list.

Next