# The CMS

Source: https://modulify.ai/docs/data/cms

Browse collections, edit rows and add content without touching SQL.

The CMS is where you read and write the contents of your site database by hand. It reads your real tables, so a collection is a table and an item is a row.

## Before you begin

Your project needs a database. If the CMS tab shows **No database**, ask the AI to create one first. [Site databases](/docs/data/databases) covers that step.

## Open the CMS

Open a project and pick the **CMS** icon in the editor's toolbar. It sits in the pill of icons next to **Preview**, and the active one shows its name beside the icon. The URL becomes `/database` under your project.

Two sub-tabs sit at the top: **Data**, which is the browser, and **Settings**.

## Pick a collection

The left sidebar is headed **Collections** and lists every table in your database, with its row count on the right. Names are title cased and pluralised, so a `blog_posts` table reads "Blog Posts" and a `post` table reads "Posts".

Once you have twenty or more collections, a **Search collections** box appears above the list. It matches on name and schema. With nothing selected, the panel reads **Select a table**, "Pick one from the sidebar to browse."

Hidden join tables used by multi reference fields are excluded by default. Turn them on in the Settings sub-tab and they appear with a small **system** badge.

## Read the table

Selecting a collection opens the table view. It does not show every column: it picks the most useful ones, usually a title or name column plus `created_at` and `updated_at`, up to five in total. Widen the panel or open a row to see the rest.

The toolbar carries a search box placeholdered with the collection name, for example "Search Blog Posts". It matches your term anywhere in the row, so searching a category name finds rows whose category column contains it. Rows load fifty at a time and the footer shows the total count with **Page X of Y** and arrow buttons when there is more than one page.

An empty collection reads **No data**, "Entities appear here once they are created." A search with no hits reads **No matches** with a prompt to clear the search.

## Add an item

Click **Add** in the toolbar. A panel slides in from the right titled after the collection, for example "New Post".

Fields are split into two sections. **Basic info** holds `title`, `name` and `slug` when the collection has them, in that order. **Custom fields** holds everything else, followed by any read only columns.

While you are creating a row, typing into `title` or `name` fills the `slug` for you, until you edit the slug yourself. Under a slug field, the CMS shows the full public URL that row will live at, and clicking it copies the URL to your clipboard.

Required fields are marked with an amber star. That comes straight from the column being `NOT NULL` in Postgres. Press **Create** to save. If something is missing or malformed, the field turns red and shows the reason, for example "Required", "Invalid JSON", or "Must be a UUID".

## Edit an item

Click any row in the table to open the same panel in edit mode. The header shows the row's title or name, or "Edit Post" when the row has neither.

Change what you need and press **Save**. `id`, `created_at` and `updated_at` are not editable: they are shown greyed out with a **read-only** label, because the database maintains them.

The expand button beside Save widens the editor to the full panel. Its tooltip toggles between **Full screen** and **Exit full screen**.

## Duplicate, export or delete an item

The three dots menu in the editor header holds:

- **Duplicate**, which opens a new unsaved row prefilled from this one. A `slug` becomes `slug-copy` and a `title` or `name` becomes "Name (Copy)", with a number appended if that is already taken on the current page.
- **Export as CSV**, which downloads just this row. This requires a paid plan and is disabled with a **Paid** badge otherwise.
- **Delete**, which asks "Delete this post?" using the collection's own name, and warns that it is permanent.

## Multilingual fields

If your site has more than one language and the AI has set the collection up for it, translatable fields collapse into one field with the language code shown next to the label, rather than appearing as separate raw columns. Use the language switcher in the Collections header, or in the editor header when it is full screen, to change which language you are editing.

The base column always holds the default language. An untranslated field shows the default language's text as its placeholder, so you can see what you are translating.

The companion columns behind those fields, and how Modulify works out which languages your site has, are covered in [Multiple languages](/docs/data/languages).

## Collection level actions

The three dots button next to **Add** applies to the whole collection:

- **Export as CSV**, paid plans only.
- **Clear data**, which asks "Clear collection data?" and warns that it permanently deletes every item while keeping the collection, its fields and its structure. If other collections link to these items, the clear is refused with "Some items are linked from other collections and cannot be cleared. Clear those collections first!"

Both are disabled while the collection is empty or a request is in flight.

## Settings

The **Settings** sub-tab holds three groups. **Collections** has a single switch, **Show system collections**, described as "Show the hidden collections used by multi-reference fields." **Export** downloads the whole database. **Danger zone** clears every collection. Both of the last two are covered in [Clearing and exporting](/docs/data/clearing-and-exporting).


## From an AI client over MCP

`list_collections`, `get_collection_schema` and `list_rows` read the CMS, and `create_row`, `update_row` and `delete_row` write to it. `list_reference_options` and `list_enum_options` are worth calling before writing a reference or enum column, since those columns refuse anything outside their allowed set.

Reading needs `data:read`, ticked by default. Writing needs `data:write`, which is not. Emptying a collection with `clear_collection` needs `sites:delete`.

See [MCP tools](/docs/mcp/tools).
## Next

- [Column types](/docs/data/column-types) explains which editor each column gets.
- [Site databases](/docs/data/databases) covers how tables get created in the first place.
- [Storage](/docs/data/storage) is where CMS image and file uploads land.