Logo

Creating a Schema

Schemas define the structure of model card and access request forms in Bailo. They are built using JSON Schema and rendered using RJSF (React JSON Schema Form).

If you're new to schemas, read Understanding Schemas first for a non-technical overview.

Common questions this page answers:

  • How do I create a schema in Bailo?
  • What question types are available in schemas?
  • How do I add conditional fields to a schema?
  • How do I test a schema?

Before you start

Bailo includes example schemas for both model cards and access requests in backend/src/scripts/example_schemas. It is important to note that these schemas contain all of mandatory fields that the application needs in order to run. These fields are hard-coded in various places in the source code. Use them as a starting point for your own schemas.

Important: Some fields are required by the application and are referenced in the source code. Always start from an example schema rather than building from scratch.

Schema structure

A schema is a JSON object with a properties field containing pages, sections, and questions.

Pages

The top-level properties define the pages (tabs) of the form:

{
  "properties": {
    "firstPage": {
      "type": "object",
      "title": "Page 1",
      "properties": {
        ...
      }
    },
    "secondPage": {
      "type": "object",
      "title": "Page 2",
      "properties": {
        ...
      }
    }
  }
}

Sections

Within each page, you can create sub-sections using nested objects:

{
  "properties": {
    "firstPage": {
      "type": "object",
      "title": "Page 1",
      "properties": {
        "sectionOne": {
          "type": "object",
          "title": "Section 1",
          "properties": {
            "questionOne": {
              "type": "number",
              "title": "Enter a number"
            }
          }
        },
        "sectionTwo": {
          "type": "object",
          "title": "Section 2",
          "properties": {
            "questionTwo": {
              "type": "string",
              "title": "Enter a string"
            }
          }
        }
      }
    }
  }
}

Question types

Schemas support several question types including text, dates, booleans, and dropdowns.

Simple text questions

"firstName": {
  "type": "string",
  "title": "First name",
  "default": "Chuck",
  "description": "This is for your first name"
}
  • type - the data type (string, number, boolean, integer)
  • title - the question text displayed to the user
  • description - help text shown below the question
  • default - a pre-filled value (optional)

If you omit the title property, the library uses the property name (e.g. firstName).

Dates

"date": {
  "type": "string",
  "title": "Date of birth",
  "format": "date"
}

Boolean questions

"isPublic": {
  "type": "boolean",
  "title": "Is this model publicly available?"
}

Dropdown selections

"category": {
  "type": "string",
  "title": "Model category",
  "enum": ["Classification", "Regression", "Generation", "Other"]
}

Hiding sections from the model card

By default, all sections are displayed on the model card page. To hide a section from the model card view while still collecting the data in the form:

"myPage": {
  "title": "Page 1",
  "type": "object",
  "properties": {
    ...
  },
  "displayModelCard": false
}

Note: This only hides the section from the model card display. The data still persists in the version metadata.

Required fields for model states

Bailo supports conditional required fields based on the state set on a model. Add the requiredByModelStates property to a question and specify which model states require it:

"modelSummary": {
  "title": "What does the model do?",
  "description": "A description of what the model does.",
  "type": "string",
  "minLength": 1,
  "maxLength": 5000,
  "requiredByModelStates": ["Development"]
}

When a user retrieves a schema, they can supply a model state alongside the schema ID. The backend sets the appropriate required properties for that state.

Dependencies (Conditional Questions)

Dependencies allow you to show or hide questions based on the answer to another question. For example, a boolean question might not need a detailed response if the answer is 'no', but if the user answers 'yes' you might want to ask for additional details.

To avoid validation errors, Bailo schemas handle dependencies differently from the standard RJSF documentation:

"myPage": {
  "title": "Page 1",
  "type": "object",
  "properties": {
    "questionOne": {
      "type": "boolean",
      "title": "True or false?"
    },
    "questionTwo": {
      "title": "More information please!",
      "type": "string"
    }
  },
  "dependencies": {
    "questionOne": {
      "oneOf": [
        {
          "properties": {
            "questionOne": {
              "enum": [false],
              "readOnly": false
            },
            "questionTwo": {
              "readOnly": true
            }
          },
          "required": ["questionOne"],
          "additionalProperties": false
        },
        {
          "properties": {
            "questionOne": {
              "enum": [true],
              "readOnly": false
            },
            "questionTwo": {
              "readOnly": false
            }
          },
          "required": ["questionOne", "questionTwo"],
          "additionalProperties": false
        }
      ]
    }
  },
  "required": ["questionOne"]
}

Why this pattern?

The standard RJSF dependency approach can cause validation errors when users change their answers. The issue is:

  1. User selects true for questionOne
  2. User enters data into questionTwo
  3. User changes their mind and selects false for questionOne
  4. User data for questionTwo remains in the form data, despite not being visible

Our approach sets additional questions to read-only instead of hiding them entirely. This preserves user data if they change their mind, while avoiding schema validation failures. The trade-off is that some unused data may persist, but it can be cleared by the user if needed.

Testing your schema

Always test a schema by uploading it, creating a test model, and working through every form page.

Before deploying a schema to production:

  1. Create the schema as a JSON file following the structure above
  2. Upload it using the Upload a Schema page
  3. Create a test model using the new schema
  4. Work through every page of the form to verify:
    • All questions appear as expected
    • Required fields are properly validated
    • Dependencies show and hide correctly
    • Section titles and descriptions are clear
  5. Check the model card view to confirm the right sections are displayed

Complete example

A minimal but complete schema with two pages, required fields, and basic structure:

{
  "type": "object",
  "properties": {
    "overview": {
      "type": "object",
      "title": "Overview",
      "properties": {
        "modelName": {
          "type": "string",
          "title": "Model name"
        },
        "description": {
          "type": "string",
          "title": "Model description"
        },
        "tags": {
          "type": "array",
          "title": "Tags",
          "items": {
            "type": "string"
          }
        }
      },
      "required": ["modelName", "description"]
    },
    "details": {
      "type": "object",
      "title": "Technical Details",
      "properties": {
        "framework": {
          "type": "string",
          "title": "ML Framework",
          "enum": ["PyTorch", "TensorFlow", "scikit-learn", "Other"]
        },
        "trainingData": {
          "type": "string",
          "title": "Training data description"
        }
      }
    }
  }
}

Related pages


Copyright © Crown Copyright 2026.