| name | chromestatus-adding-a-field |
| description | How to add a new field to a feature across the entire stack (Data, API, and Frontend). |
Adding a Field to a Feature
This guide explains how to add a new field to a feature entry, ensuring it is properly persisted in the database, exposed via the API, and editable in the frontend.
1. Data Layer (Backend)
The primary data model for features is FeatureEntry located in internals/core_models.py.
Add Property to FeatureEntry
Add your new field as an ndb property.
class FeatureEntry(ndb.Model):
my_new_field = ndb.StringProperty()
2. API Layer (Backend)
Update api_specs.py
The FeaturesAPI uses api/api_specs.py to map request fields to database properties and handle types.
FEATURE_FIELD_DATA_TYPES: FIELD_INFO_DATA_TYPE = [
('my_new_field', 'str'),
]
Update Converters (Optional)
If your field needs custom formatting for the JSON response (e.g., date to string), update api/converters.py. Most simple types are handled automatically by to_dict.
def feature_entry_to_json_verbose(fe: FeatureEntry, ...):
d: VerboseFeatureDict = {
'my_new_field': fe.my_new_field,
}
3. OpenAPI Specification
Update openapi/api.yaml if you want the field to be part of the official API documentation and generated models.
4. Frontend Layer
Define Form Field Metadata
Add the field's metadata (label, help text, component type) in client-src/elements/form-field-specs.ts.
export const ALL_FIELDS: Record<string, Field> = {
my_new_field: {
type: 'input',
attrs: TEXT_FIELD_ATTRS,
label: 'My New Field',
usage: ALL_INTENT_USAGE_BY_FEATURE_TYPE,
help_text: html`Explain what this field is for.`,
},
};
Add to Form Definitions
Include the field in the relevant forms in client-src/elements/form-definition.ts.
export const FLAT_METADATA_FIELDS: MetadataFields = {
name: 'Feature metadata',
sections: [
{
name: 'Feature metadata',
fields: [
'my_new_field',
],
},
],
};
5. Server-Side Form Display & Formatting (Backend Sync)
To enable the backend to understand and correctly display the form fields (even when not generating full editing forms on the server), the TypeScript form and field specifications MUST be mirrored in the Python backend files located in the pages/ directory.
Update pages/form_field_specs.py
Add the field's type and label to ALL_FIELDS in pages/form_field_specs.py.
ALL_FIELDS: dict[str, FieldSpec] = {
'my_new_field': {
'type': 'input',
'label': 'My New Field',
},
}
Update pages/form_definitions.py
If the field is used in any feature guide stage, add it to the corresponding form definition(s) and/or FORMS_BY_STAGE_TYPE in pages/form_definitions.py. If it is a general feature metadata field, add it to FLAT_METADATA_FIELDS or FLAT_ENTERPRISE_METADATA_FIELDS.
FLAT_METADATA_FIELDS: FormDef = {
'name': 'Feature metadata',
'sections': [
{
'name': 'Feature metadata',
'fields': [
'my_new_field',
],
},
],
}
6. Verification
- Backend Tests: Run
npm test to ensure NDB properties and converters work.
- Form Display Tests: Run
./cs-env/bin/pytest pages/form_definitions_test.py to ensure that all defined fields in form_field_specs.py are properly referenced in form_definitions.py and vice versa, and that static typing checks (mypy) and linting (ruff) pass on the new definitions.
- Frontend: Run
npm run webtest or manually verify the new field appears in the feature edit form.
- API: Manually check
/api/v0/features/{id} to see if the field is present.