> ## Documentation Index
> Fetch the complete documentation index at: /docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Content and CMS

> Define editable content in code, add entries, and make it available to teammates in Studio.

Your coding agent defines the shape of your content. Your team fills in and updates that content in Studio.

Use a **Single** for one set of content, such as a homepage or site settings. Use a **Collection** for repeated entries, such as posts, products, or team members.

## Add editable content

**1. Create a schema**

Add `src/schemas/BlogPost.json`. The PascalCase filename must match the schema UID. Ask your coding agent to load the `fimo-code` schema reference before writing the file.

**2. Register the schema**

```bash theme={null}
fimo schemas push BlogPost
```

This updates the current Branch and generates the framework-specific client. Do not edit generated files.

**3. Add content**

For a Collection entry:

```bash theme={null}
fimo entries create BlogPost \
  --body '{"data":{"slug":"first-post","title":"Hello"}}'
```

For a Single:

```bash theme={null}
fimo singles update HomePage \
  --body '{"data":{"title":"Welcome"}}'
```

**4. Render it**

Ask your coding agent to load the matching `fimo-code` content and framework references. The generated client reads the content, and Fimo's rendering components keep it editable in Studio.

## Query content with SQL

Use `fimo entries query` for read-only queries over `entries`. Standard PostgreSQL syntax works, including `substring`, `extract`, and `trim` with `FROM`, and `position`, `strpos`, and `substr`:

```bash theme={null}
fimo entries query --sql "SELECT substring(slug from 1 for 10) AS prefix, extract(year from created_at) AS year, trim(from slug) AS slug FROM entries"
```

Queries can read `entries` through joins, subqueries, and CTEs. Writes, other tables, and PostgreSQL system catalogs are rejected, including `information_schema` and any name that starts with `pg_`. Functions outside the supported set are unavailable.

## Manage schemas

```bash theme={null}
fimo schemas list
fimo schemas get BlogPost
fimo schemas push BlogPost
```

Pushing all schema files as one batch supports models that reference each other:

```bash theme={null}
fimo schemas push
```

> [!WARNING]
>
> Review schema changes before pushing them to a Branch with content. Deleting fields, changing references, and
> switching between a Collection and a Single can remove or reshape stored values.

## Set rules for your content

Add a `description` to a schema for rules about the whole content type, and to a field for rules about that field. Agents follow these rules when they write or generate that content, and editors see them in Studio.

```json theme={null}
{
  "uid": "BlogPost",
  "name": "Blog posts",
  "description": "Every post opens with the reader's problem and ends with one next step.",
  "fields": {
    "title": {
      "type": "string",
      "required": true,
      "description": "Say the outcome, not the topic. Under 60 characters."
    },
    "cover": { "type": "media", "description": "Flat illustration on the brand background, with no text." }
  }
}
```

Run `fimo schemas push` to apply them. Changing a description does not change stored content. Keep rules for the whole site, such as your tone of voice, in [site knowledge](/docs/studio/project-settings.md#site-knowledge).

You can also ask an agent to add a rule: "from now on, blog covers are flat illustrations with no text".

## Store one image or a gallery

Media fields default to one object. Arrays need `multiple: true` in `fields`, even with one image:

```json theme={null}
{
  "cover": { "type": "media" },
  "gallery": { "type": "media", "multiple": true }
}
```

## Link entries with references

Use `target` when a reference always points to one content type. Use `targets` when each value may point to one of several content types:

```json theme={null}
{
  "author": { "type": "reference", "target": "Author" },
  "featured": { "type": "reference", "targets": ["Article", "Video"], "many": true }
}
```

A polymorphic value includes the selected content type and stable entry ID:

```json theme={null}
{ "contentType": "Article", "id": "<article-id>" }
```

Fixed and polymorphic references use the same field definitions and value shapes inside blocks. Nested references return their raw identities and cannot currently be populated or filtered.

## Store true or false flags

```json theme={null}
{ "featured": { "type": "boolean", "default": false } }
```

A read returns a tracked value, not a plain `true`/`false`, so Studio knows which
field an editor clicked. Render it with the generated `<Boolean>` component, and
read `.value` everywhere else:

```tsx theme={null}
return (
  <article>
    <Boolean value={post.featured} />
    {post.featured?.value ? <Badge /> : null}
  </article>
);
```

> [!WARNING]
>
> `if (post.featured)` is always true, even when the stored value is `false`. Every tracked value is an object, and
> JavaScript treats every object as truthy — TypeScript reports no error either. Read `.value` in conditions,
> comparisons, attributes, and calls into other libraries. A field without `required: true` reads as
> `post.featured?.value`.

## Store dates and exact moments

Use `date` for a calendar day and `datetime` for an exact moment. A `datetime`
value must include an ISO 8601 UTC offset, such as `Z` or `+02:00`.

```json theme={null}
{
  "uid": "Event",
  "name": "Events",
  "fields": {
    "title": { "type": "string", "required": true },
    "startsAt": { "type": "datetime", "required": true }
  }
}
```

Fimo preserves the complete instant when it stores, filters, and sorts the
field. Render it with the generated `<DateTime>` component. See [frameworks](/docs/cli/frameworks.md)
for the component surfaces.

## Check that your site reads a content type

`fimo validate` reports a content type that nothing in the site appears to read:

```text theme={null}
⚠ Content type "Job" has no observed consumer in this preview: no file outside
  src/schemas imports its generated client "src/schemas/Job" or names "Job".
  Its entries can be live in Fimo and never reach the site.
```

This is common after a migration: the schema and its entries arrive before the page that renders them. The warning does not fail the command, and the check reads only the files in the site. Code that lives outside it, or a content type selected at run time, is invisible to it — so treat the warning as a question, not a verdict.

With `--json`, the same warnings are in `warnings[]` as text and in `data.warnings[]` with a stable `code`, the schema `file`, and the evidence the check used.

## Manage entries and Singles

```bash theme={null}
fimo entries list BlogPost --sort -publishedAt
fimo entries list BlogPost --limit 20 --cursor <next-cursor>
fimo entries list BlogPost --all-pages
fimo entries get BlogPost <id>
fimo entries get BlogPost <id> --populate author,cover
fimo entries create BlogPost --file body.json
fimo entries update BlogPost <id> --body '{"data":{"title":"Updated"}}'
cat body.json | fimo entries update BlogPost <id> --stdin
fimo entries delete BlogPost <id>

fimo singles get HomePage
fimo singles update HomePage --file homepage.json
```

`entries create` and `entries update` require exactly one of `--body <json>`, `--file <path>`, or `--stdin`. Each source takes a `{"data":{...}}` JSON envelope.

`fimo singles get` reads an existing Single: it returns not found when the Single has no content yet, and `fimo singles update` creates it.

Creating a Single through `fimo entries create` or `fimo entries bulk-create` returns `SINGLE_CONTENT_TYPE` in the CLI's `--json` error envelope. Use `fimo singles update <typeName>` to create or update its content. REST callers receive HTTP 400 with `code: "single_content_type"`; the response message retains the update path, `PUT /documents/<typeName>`.

Use `--locale <locale>` for a non-default language. A translated variant of an existing Collection entry also needs its `documentId` when you create it. See [Locales](/docs/cli/locales.md).

Entry lists use the shared pagination flags. The response includes `nextCursor` when another page exists. The older `--offset` flag remains accepted for existing scripts.

`--populate` on `entries list`, `entries get`, and `singles get` takes comma-separated top-level field names. Reference fields return the linked entry, media fields return the asset's current facts such as width and height, and naming a blocks field populates the media inside it. Nested paths are not supported. Run `fimo schemas get BlogPost --json` to see field names and types.

Studio offers the everyday editing experience. Open **Content → Collections** or **Content → Singles** to add and update values without running commands.

For field definitions, filters, bulk actions, rich text, references, and every command option, see the [CLI reference](/docs/reference/cli.md).

## What's next

> [card] [CMS in Studio](/docs/studio/cms.md)
>
> Edit content without using the CLI.

> [card] [Media](/docs/cli/media.md)
>
> Upload files for media fields.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.