strataDocs

Manifest & Export

The JSON manifest is Strata's primary export format — a validated, self-contained description of your Drupal content architecture.

The manifest is designed to be consumed by the companion Drush package (strata/strata-sync), but it's also a useful reference document on its own. It follows JSON Schema 2020-12 and is validated against the schema before export.

Design principles

  • Declarative, not imperative. The manifest describes what should exist, not how to create it. The Drush command decides creation order and API calls.
  • Machine names are primary identifiers. Entries are identified by machine name, not UUIDs. Drupal's config UUIDs are generated at import time.
  • Self-contained. Everything needed to understand the architecture is included: entries, relationships, module dependencies, and export metadata.
  • Supports full and differential exports. A full export includes every active entry. A differential export includes only changes since a reference point.
  • Forward-compatible. Unknown sections are ignored by handlers that don't support them.

Top-level structure

{
  "manifest_version": "2.0",
  "export_type": "full",
  "exported_at": "2026-09-05T14:30:00Z",
  "exported_by": {
    "name": "Jane Smith",
    "email": "[email protected]"
  },

  "project": {
    "name": "Client Website Redesign",
    "slug": "client-redesign",
    "organization": "Acme Digital Agency",
    "adapters": {
      "drupal": { "version": "11" }
    }
  },

  "module_dependencies": [ ... ],
  "sections": [ ... ],

  "registry": { "entries": [ ... ], "modules": [ ... ] }
}

Metadata fields

FieldTypeDescription
manifest_versionstring"2.0" on current exports. "1.0" and "1.1" are still accepted on import
export_typestring"full" or "differential"
exported_atISO 8601Timestamp of the export
exported_byobjectName and email of the exporting user
registryobjectOptional. Project-scoped registry entries and modules (never the built-in core catalogue). Omitted from differential exports

Export types

Full export

A full export includes every active entry across all section types. Each entry has change_type: "full", which tells the Drush command to ensure the entity exists with these exact values — creating if missing, updating if different.

Full exports include the registry block (project-scoped custom entries and modules) and auto-synced module dependencies. Sections are emitted in dependency order so referenced entries are always defined before referencing entries.

Differential export

A differential export includes only changes since a reference changeset. Each entry gets a specific change type:

  • "created" — new entry, create it
  • "updated" — modified entry, update it. Includes a changed_fields array listing which properties were modified. The data contains the complete current state (not a diff).
  • "deleted" — removed entry, delete or disable it

Differential exports include a differential metadata block with the reference changeset, count of included changesets, and total change count. The registry block is omitted entirely from differential exports because registry rows are not changesetted.

Parent entries are automatically included when any of their children have changed, ensuring the manifest stays structurally valid.

Module dependencies

Strata automatically detects which contributed modules your architecture requires based on the field types, widgets, and formatters you use. Dependencies are synced before every export. Each entry includes the Composer package name and which fields require it.

"module_dependencies": [
  {
    "name": "paragraphs",
    "package": "drupal/paragraphs",
    "required_by": [
      "field_lp_components (entity_reference_revisions on Landing Page)"
    ]
  },
  {
    "name": "media_library",
    "package": "drupal/media_library",
    "required_by": [
      "field_art_hero_image widget (media_library_widget on Article)"
    ]
  }
]

Sections

The manifest is organized into sections, one per entity type. Each section contains entries of that type, processed by the corresponding handler in the Drush package. Sections are emitted in dependency order:

Section typeHandlerDescription
taxonomy_vocabulariescore:taxonomy_vocabularyVocabularies with fields and permissions
media_typescore:media_typeMedia types with fields and source config
paragraph_typesparagraphs:paragraph_typeParagraph types (requires drupal/paragraphs)
content_typescore:node_typeNode types with fields, displays, and permissions
block_typescore:block_content_typeBlock content types with fields
viewscore:viewViews with displays and configuration
user_rolescore:user_roleUser roles and permissions
menuscore:menuCustom menus
text_formatscore:filter_formatText filter formats
date_formatscore:date_formatNamed date format patterns
image_stylescore:image_styleImage style presets
sdcscore:sdcSingle Directory Components with props and slots

Entry structure

In v2.0, each entry separates CMS-neutral (canonical) data from Drupal-specific adapter data:

{
  "change_type": "full",
  "machine_name": "article",
  "data": {
    "label": "Article",
    "description": "Time-sensitive content like news and blog posts.",
    "status": true
  },
  "adapters": {
    "drupal": {
      "new_revision": true,
      "preview_mode": "optional",
      "display_submitted": true,
      "form_displays": [ ... ],
      "view_displays": [ ... ],
      "permissions": [ ... ]
    }
  },
  "fields": [ ... ]
}

Canonical keys (label, description, status) stay in data. Drupal-specific keys and nested arrays (form_displays, view_displays, permissions) move under adapters.drupal. Views entries include displays. SDC entries include props and slots. Internal-only keys like notes, field_prefix, and computed counts are stripped on export.

Field entries

Fields are nested within their parent entity. In v2.0 each field entry adds a canonical type and qualifiers, and splits data the same way as bundle entries:

{
  "machine_name": "field_article_body",
  "type": "text",
  "qualifiers": { "long": true },
  "data": {
    "label": "Body",
    "required": true,
    "cardinality": 1,
    "translatable": false,
    "help_text": "The main body content"
  },
  "adapters": {
    "drupal": {
      "field_type": "text_long",
      "widget": "text_textarea",
      "formatter": "text_default",
      "shared_field_storage": false
    }
  }
}

Canonical keys (label, cardinality, required, etc.) stay in data. Drupal-specific keys (field_type, widget, formatter, etc.) move under adapters.drupal. The type and qualifiers are a canonical type vocabulary mapping 22 Drupal field types to 12 semantic types (text, number, boolean, list, email, link, telephone, datetime, daterange, image, file, reference).

The shared_field_storage boolean is derived on export from reuse-group analysis. When a field has the same machine name across multiple bundles via explicit reuse, the Drush command recognizes shared field storage and creates a single FieldStorageConfig with multiple FieldConfig instances.

Registry block

The manifest includes an optional registry block containing the project's own custom registry entries and modules. The block has two collections — there is no types key because registry types are global taxonomy, identical everywhere.

"registry": {
  "entries": [
    {
      "type_slug": "field_types",
      "machine_name": "address",
      "label": "Address",
      "module": "address",
      "settings_schema": { ... }
    }
  ],
  "modules": [
    {
      "machine_name": "address",
      "label": "Address",
      "package_name": "drupal/address",
      "source": "contributed"
    }
  ]
}

Only project-scoped rows are exported — the globally seeded core catalogue is never included, since every destination has its own seed. Import is additive (upsert on natural key, never deletes), processes modules before entries, and reports unresolvable type slugs to the user.

Validation

Strata validates manifests against the appropriate JSON Schema (v1.1 or v2.0) using AJV 2020 before serving them. Import accepts versions 1.0, 1.1, and 2.0 — older manifests still validate and import correctly.

Validation checks include:

  • Required fields and correct types
  • Valid machine name format (lowercase, underscores, no spaces)
  • Valid handler identifiers
  • Referential integrity between fields and their parent entries
  • Module dependency completeness
  • Conditional requirements (e.g. differential block required when export_type is “differential”)

XLSX spreadsheet export

Strata also exports your content architecture as an XLSX spreadsheet, useful for sharing with stakeholders who prefer a traditional spreadsheet view.

Default layout

One sheet per visible top-level tab (Content Types, Taxonomy Vocabularies, Media Types, etc.), plus one sheet per inline tab that has entries (Fields, View Displays, etc.). Columns are derived from each tab's column schema, sorted by column order. Inline tabs include a “Parent” column showing the parent bundle name.

By-bundle layout

One sheet per bundle entry (e.g. “Article”, “Blog Post”) showing that bundle's fields. Useful when each content type needs its own page for review.

Both layouts include styled headers, auto-filters, type-aware cell formatting (booleans as Yes/No, selects as display labels, entry references as resolved labels), and formula-injection protection. The file is named {project-slug}-data-dictionary-{date}.xlsx.