---
sidebar_label: Catalog specifications
doc_id: 5ea2e718-5138-4282-be17-d621b96f0dd5
description: >-
  Guide for defining catalog specifications that control metadata structure and
  validation for nullplatform entities.
keywords:
  - catalog specification
  - metadata
  - JSON schema
  - validation
  - nullplatform
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# Define catalog specifications

A **catalog specification** defines the structure, validation rules, and display behavior for metadata attached to entities in nullplatform, like applications, builds, and namespaces.

Each specification acts as a **template**: it tells the platform what fields should be available for a given entity, how those fields should behave (e.g., enum vs. free text), and how they should be displayed.

Once a spec is defined, nullplatform can:
- Autogenerate form sections during entity creation
- Render editable metadata in dashboards
- Enforce validation for all updates—whether from the UI or API 

:::info Catalog specs are created via API
Once defined, they automatically power the UI for forms and metadata display.
:::


### What a catalog specification includes

Each spec is a JSON object with the following fields:

| Field         | Description                                                                    |
| ------------- | ------------------------------------------------------------------------------ |
| `entity`      | The entity type the spec applies to (e.g. `build`, `application`, `namespace`) |
| `metadata`    | A unique key for this metadata group (e.g. `coverage`, `quality_insights`)     |
| `schema`      | A [JSON Schema](https://json-schema.org) defining the fields and rules         |
| `nrn`         | The scope this spec applies to (e.g. an org, namespace, or account)            |
| `name`        | Human-readable name (used in forms and dashboards)                             |
| `description` | Optional description for users filling out the metadata                        |


## How to create a specification (API)

You can create a spec with a [POST request to create a catalog specification](/docs/api/catalog-specification-create)

```bash
curl -L -X POST 'https://api.nullplatform.com/metadata/metadata_specification' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{
  "name": "Namespace tags",
  "description": "Add tags as key-value object to namespace entities",
  "nrn": "organization=1",
  "entity": "namespace",
  "metadata": "tags",
  "schema": {
    "type": "object",
    "properties": {
      "my_string_property": {
        "type": "string",
        "tag": true
      },
      "my_number_property": {
        "type": "number",
        "default": 0,
        "tag": "my_custom_tag_name"
      },
      "my_object_property": {
        "type": "object",
        "properties": {
          "my_nested_property": {
            "type": "string"
          }
        }
      }
    },
    "required": [
      "my_string_property"
    ],
    "additionalProperties": false
  }
}'
```


## Example: autogenerate forms during entity creation

When you create an application, build, or namespace, nullplatform checks for a matching catalog specification.
If one exists, it automatically adds a metadata form to the creation flow, with no manual UI work needed.

Users fill out fields defined in the schema, with live validation. Once saved, metadata is attached to the entity
and available in dashboards or for editing later.

This means structured **data collection becomes a natural part of onboarding**, with no extra steps.

#### A metadata form is shown if:

- A catalog spec exists for the entity type (`application`, `build`, or `namespace`)
- The spec has at least one field
- That field is visible on creation (`visibleOn: ["create"]`) or has no `visibleOn` at all

If no matching spec is found, the form step is skipped.

*Example of a form to create a namespace:*

```json
{
  "entity": "namespace",
  "metadata": "operational",
  "nrn": "organization=1:account=2",
  "description": "Add operational and organizational information as tags to namespace entities",
  "name": "Namespace Operational Tags",
  "schema": {
    "type": "object",
    "properties": {
      "business_unit": {
        "type": "string",
        "title": "Business Unit",
        "description": "The business unit or division owning this namespace",
        "tag": true
      },
      "compliance": {
        "type": "string",
        "visibleOn": [
          "read",
          "update",
          "create",
          "list"
        ],
        "enum": [
          "PCI",
          "HIPAA",
          "GDPR",
          "None"
        ],
        "title": "Compliance Requirements",
        "description": "Regulatory standards applicable to this namespace",
        "tag": "compliance_tag"
      },
      "deployment_frequency": {
        "type": "string",
        "enum": [
          "daily",
          "weekly",
          "monthly",
          "on_demand"
        ],
        "title": "Deployment Frequency",
        "description": "How often this namespace is deployed",
        "tag": true
      },
      "incident_history": {
        "type": "number",
        "title": "Incident Count (Last 90 days)",
        "description": "Number of incidents involving this namespace in the last 90 days",
        "tag": true
      },
      "last_audit": {
        "type": "string",
        "format": "date",
        "title": "Last Audit Date",
        "description": "The most recent date this namespace was audited"
      }
    },
    "required": [
      "business_unit",
      "deployment_frequency"
    ],
    "additionalProperties": false
  }
}
```


## Example: application type spec

This example defines a simple dropdown for selecting an application type when creating or editing an app.

```json
{
  "name": "Application type",
  "entity": "application",
  "metadata": "apptype",
  "nrn": "organization=123",
  "schema": {
    "type": "object",
    "properties": {
      "application_type": {
        "type": "string",
        "oneOf": [
          { "const": "public", "title": "Public Application" },
          { "const": "private", "title": "Private Application" },
          { "const": "internal", "title": "Internal Application" }
        ],
        "visibleOn": ["create", "read", "update"]
      }
    },
    "required": ["application_type"],
    "additionalProperties": false
  }
}
```

Once saved, this spec:
- Renders a dropdown during app creation.
- Appears under the **Metadata** panel on the application dashboard.
- Can be edited later using the **Show all** button.


## Example: build quality insights

This spec defines metrics shown in the build detail view (like `coverage_percent`, `technical_debt_minutes`, and
`complexity`):

```json
{
  "name": "Build Quality Insights",
  "entity": "build",
  "metadata": "quality_insights",
  "nrn": "organization=123",
  "schema": {
    "type": "object",
    "properties": {
      "technical_debt_minutes": {
        "type": "integer",
        "description": "Time-based tech debt metric",
        "visibleOn": ["create", "update", "read", "list"]
      },
      "coverage_percent": {
        "type": "integer",
        "description": "Coverage % for this build",
        "visibleOn": ["create", "update", "read", "list"]
      },
      "is_stable": {
        "type": "boolean",
        "description": "Indicates whether the build is considered stable.",
        "visibleOn": ["create", "update", "read", "list"]
      },
      "complexity": {
        "type": "integer",
        "description": "Code complexity score",
        "visibleOn": ["read", "list"]
      },
      "vulnerabilities": {
        "type": "integer",
        "description": "Known vulnerabilities in this build",
        "visibleOn": ["read", "update"]
      }
    },
    "required": ["coverage_percent", "technical_debt_minutes", "complexity","is_stable", "vulnerabilities"],
    "additionalProperties": false
  }
}
```

Once attached to a build, this spec:

- Renders directly in the "Quality Insights" section of the build dashboard.
- Some fields are editable, some are read-only.
- Taggable and usable in filters if `tag` is also defined.

## Adding catalog data to list views

You can display catalog fields directly inside an entity list view, by adding `"list"` to a field’s `visibleOn` configuration.

> ℹ️ This feature is only available for **build** and **deployment** entities.

When `"list"` is included, the platform automatically creates a new column in the corresponding table and renders the field value for each entity.

The configuration shown in the example spec above produces the columns shown in the following screenshot, enabling teams to assess build health directly from the overview page without opening every build.

<img alt="catalog build intro ui" src="/img/catalog/catalog-build-overview2.png" width="100%" className="helper-image" />

:::tip Column naming rules
List-view columns follow the same naming hierarchy used across all schema/UI schema rendering in nullplatform.

When generating the column label, the platform checks:

1. **`uiSchema` (UI schema)** — If the field defines a custom label, it takes priority. See our [UI schema docs](/docs/json-ui-schema/ui-schema) for more info on this.
2. **`title` (JSON Schema)** — If no UI label is present, the schema’s `title` is used.  
3. **Property key (humanized)** — If neither a UI label nor a title is provided, nullplatform uses the property name and automatically humanizes it (e.g., `is_stable` → **Is Stable**).
:::


## Tagging fields for filters and dashboards

You can mark any field in a schema as a **tag**, which makes it available for:

- Dashboard filtering
- Metadata-based search
- Integration with third-party tools (e.g., FinOps, inventory systems)

To tag a field, use the `"tag"` key:

```json
{
  "business_unit": {
    "type": "string",
    "tag": true
  },
  "platform_type": {
    "type": "string",
    "enum": ["web", "mobile"],
    "tag": "platform"
  }
}
```

- `"tag": true` uses the field name as the tag key.
- `"tag": "custom_name"` lets you define your own key.

For a complete guide on tagging—including use cases, API queries, and external integrations—see [Tags in catalogs](/docs/catalog/tags).



## Next steps

Once your catalog spec is defined:

- [Attach metadata to entities via UI or API](/docs/catalog/instances)
