Content Manager Layout Synchronization#
syncLayouts reconciles persisted Content Manager layout configurations against the current content-type or component schema on every Strapi server bootstrap. Its job is to keep the stored list and edit view layouts consistent with the live schema — adding newly created fields, dropping removed or invalid ones, and handling field type changes — without reordering fields that were placed intentionally by an admin.
Where it lives#
| File | Purpose |
|---|---|
layouts.ts | syncLayouts, createDefaultLayouts, appendToEditLayout |
utils/configuration/index.ts | syncConfiguration — calls syncLayouts alongside syncSettings and syncMetadatas |
services/configuration.ts | Generic configuration-service factory; drives syncConfigurations() |
services/content-types.ts | Delegates syncConfigurations() to the factory |
services/components.ts | Same, for components |
bootstrap.ts | Calls syncConfigurations() for both content-types and components on startup |
Call chain#
On every server start, bootstrap.ts calls :
bootstrap
→ components.syncConfigurations()
→ content-types.syncConfigurations()
→ configurationService.syncConfigurations()
→ syncConfiguration(conf, schema) [per content-type/component]
→ syncLayouts(conf, schema) ← this article
syncConfiguration returns a merged object of { settings, layouts, metadatas } , so syncLayouts only owns the layout slice.
What syncLayouts does#
The function signature is syncLayouts(configuration, schema) . Its logic, in order:
-
Empty guard — if
configuration.layoutsis empty, returnscreateDefaultLayouts(schema)immediately . -
List layout cleanup — filters the stored
listarray down to attributes that still passisListable(schema, attr). Removed or non-listable fields are dropped silently. -
editRelationsbackward compatibility — legacy configurations stored relation fields separately ineditRelations; these are migrated intoelementsToReAppendso they are re-inserted at the end of the edit layout . The TODO comment marks this for removal in V5. -
Edit layout row-by-row validation — each
{name, size}element in the stored edit rows is checked:- Fields whose attribute no longer exists in the schema (fails
hasEditableAttribute) are dropped . - Fields whose type changed (e.g.
string → json) and whose storedsizeis now disallowed by the new type's size rules are moved toelementsToReAppendinstead of being kept in-place . This prevents invalid row layouts. - Valid fields are kept in their original row position .
- Fields whose attribute no longer exists in the schema (fails
-
Re-appending displaced fields —
appendToEditLayoutadds the accumulatedelementsToReAppendto the end of the cleaned edit layout, using the field's default size and theMAX_ROW_SIZE = 12grid constraint . -
New attributes — fields present in
schema.attributesbut absent fromconfiguration.metadatasare considered new. They are appended to the list (up toDEFAULT_LIST_LENGTH = 4) and to the edit layout . -
Fallback — if either cleaned layout is empty after all processing, the corresponding
createDefault*Layoutis used .
Layout data model#
- List layout (
list): a flatstring[]of attribute names shown in the content-manager list view. Capped at 4 items by default . - Edit layout (
edit): aRow[][]— an array of rows, each row an array of{name: string, size: number}objects. Sizes are integers summing to at mostMAX_ROW_SIZE = 12per row .
Field size rules#
Field sizing is delegated to the field-sizes service . Each field type has a default size and an isResizable flag. Non-resizable fields (e.g., json) must always use their fixed size; placing them at a stored size that differs triggers removal and re-append.
Custom fields use their registered customField key for size lookup rather than their base type . This is exercised in the custom field size test.
Tests#
layouts.test.ts covers three scenarios: default generation from empty config, appending a new field to an existing layout, and correct sizing for custom fields.