Reference

Resource metadata

Root settings, system fields, resource rules and schema examples.

.meta file

Defines the structure and behavior of a resource. All fields must be explicitly configured.

{
  "fields": {
    "title": {
      "name": "Title",
      "type": "text",
      "required": true
    },
    "title_slug": {
      "name": "URL slug",
      "type": "slug",
      "source": "title"
    },
    "published": {
      "name": "Published",
      "type": "boolean"
    },
    "body": {
      "name": "Body",
      "type": "html",
      "buttons": "h2,h3,h4,bold,italic,orderedlist,unorderedlist,quote,anchor",
      "media": true,
      "media_sizes": "sm-90,md-70,lg-60,xl-50,xxl-40",
      "admin_col": false
    },
    "sort_order": {
      "name": "Sort order",
      "type": "text",
      "admin_col": false
    }
  },
  "sort": {
    "field": "sort_order",
    "flags": "numeric",
    "order": "asc"
  }
}

Root-level .meta configuration

Key Description
sort Default sort (field, flags: string/numeric, order: asc/desc)
validate Validation rules (e.g. natural-short-text)
languages Enabled languages for this resource
ai_prompts Per-field AI translation instructions
name Object with optional singular and plural labels used by [#resource-name#], admin headings, and Nimbly-bar resource entries. Labels fall back to names derived from the resource ID. Example: {"singular": "Member", "plural": "Members"}.
nimblybar Boolean controlling whether the resource appears in the Nimbly-bar Resources menu. Regular resources are visible by default; users and roles are hidden by default. Set true to include or false to hide explicitly. The current user still needs view-<resource>.
actions Object with optional view_url and url keys. view_url overrides the generic admin View action (default /nb-admin/{resource}/{uuid}?view=1); url adds the separate “View on site” action. Both support [#record.<field>#] substitutions. Example: {"view_url": "/review/?id=[#record.uuid#]", "url": "[#base-url#]/articles/[#record.title_slug#]"}.
events Resource lifecycle event declarations. Supported keys: create, update, delete. Values are arrays of named events or job:<type> queue entries. See below.
splitdir Boolean. When true, records are stored in a two-level subdirectory tree by UUID prefix for filesystem performance at scale (> ~10,000 records). See §12 API - Scalability.
index Array of field names to index. Creates fast lookup paths for those fields. See §4 Indexes below.
upsert Boolean. When true, data_update() (and therefore PUT /api/v1/{resource}/{uuid}) creates a missing record instead of failing. Use only for key-value-style resources where "record may not exist yet" is the normal, expected state (e.g. core's .config, used for per-page settings) - not for regular content resources, where updating a non-existent record should stay an error.
self_edit users only. Comma-separated fields a user may save on their own record through PUT /api/v1/users/{uuid}. Default: name. Anyone who may edit users (edit-users, manage-users, admin) saves every field.
hidden Comma-separated fields the API never returns: not in a list, a single record, the answer to a create or update, or an export. They are still stored and saved as usual; read them in PHP with data_read(). Fields named in encrypt are always hidden. For users, password, salt, api, password_reset_token and change_email_token are hidden by core, whatever the .meta says.
keep_shortcodes Boolean. By default a shortcode tag in a value that is written to a record is stored as text ([# and #] become HTML entities), whoever writes it: the API, an import, an agent, a form handler or data_create() / data_update() in a library. It then displays as typed and is never run when the value is printed inside another shortcode. Values a record already holds and the .meta itself are not touched. Set true only for a resource that no template prints and that must hold its text exactly as written; core does so for the job queue and the agent's own records.
history Boolean. Whether changes to the resource's records are kept, see Record history below. Default: on for regular resources, off for users and for hidden resources other than .content, .config and .navigation.
sitemap Lazy sitemap declaration. url is a string or language-keyed URL template; optional published names a publication field and optional each names one array field to expand. Rendering exposes record, language, and sitemap_item.

System fields (auto-managed)

Every record automatically has: uuid, _created, _modified, _created_by, _modified_by. Never define these in .meta.

Resource conventions (required)

These rules are mandatory for all resources unless explicitly stated otherwise.

Always include:

  • "required": true on all name/title fields
  • published boolean field on content resources
  • sort_order field + sort config on list resources (partners, logos, cards, team members, etc.)
  • "admin_col": false on images, html, urls, large text, and technical fields like sort_order

Always consider:

  • Does this resource need a published field?
  • Does ordering matter? Add sort_order + sort
  • Is this linked from a URL? Add a slug field and list it in index
  • Does any field need to be unique? Add it to unique; a unique field is indexed by itself
  • Does the admin overview need a specific column order? Use admin_columns, including _modified and _created when useful
  • Does content need to be translated? Add languages and i18n per field
  • Can this be smaller while still fully solving the current requirement?
  • Can existing system metadata or a single field index solve this without extra custom fields?

Admin visibility - fields to hide by default:

  • images
  • html content
  • urls
  • large text fields
  • sort_order and other technical fields

Production-ready .meta examples

Example A: Partners (list with sorting)

{
  "fields": {
    "title": {
      "name": "Partner name",
      "type": "text",
      "required": true
    },
    "published": {
      "name": "Published",
      "type": "boolean"
    },
    "logo": {
      "name": "Logo",
      "type": "image",
      "admin_col": false
    },
    "website": {
      "name": "Website",
      "type": "url",
      "admin_col": false
    },
    "sort_order": {
      "name": "Sort order",
      "type": "text",
      "admin_col": false
    }
  },
  "sort": {
    "field": "sort_order",
    "flags": "numeric",
    "order": "asc"
  }
}

Example B: Articles (content with date sorting)

{
  "fields": {
    "title": {
      "name": "Title",
      "type": "text",
      "required": true
    },
    "published": {
      "name": "Published",
      "type": "boolean"
    },
    "featured": {
      "name": "Featured",
      "type": "boolean"
    },
    "date": {
      "name": "Date",
      "type": "date"
    },
    "main_img": {
      "name": "Image",
      "type": "image",
      "admin_col": false
    },
    "intro": {
      "name": "Intro",
      "type": "html",
      "buttons": "bold,italic",
      "admin_col": false
    },
    "main_text": {
      "name": "Main text",
      "type": "html",
      "buttons": "h2,h3,h4,bold,italic,orderedlist,unorderedlist,quote,anchor",
      "media": true,
      "media_sizes": "sm-90,md-70,lg-60,xl-50,xxl-40",
      "admin_col": false
    }
  },
  "sort": {
    "field": "date",
    "flags": "string",
    "order": "desc"
  }
}

Example C: Admin overview columns

Use admin_columns to control the admin table column order. This can include built-in system columns _modified and _created.

{
  "admin_columns": ["email", "_modified", "_created"],
  "sort": {
    "field": "_modified",
    "flags": "numeric",
    "order": "desc"
  }
}

View this page as Markdown