Skip to content

The schema system

Drupal display modes become schemas that drive field rendering, generated once at startup and reused to narrow the JSON:API query.

After routing resolves which entity to render, the next question is which fields, in what order, with what settings. Druxt's answer is unusual: it doesn't invent a frontend field configuration, it reads Drupal's display modes.

The druxt-schema package turns view modes and form modes into schemas: plain objects describing the fields to render and the components to render them with.

An example schema

A schema for an article's teaser view mode looks conceptually like:

{
  id: 'node--article--teaser--view',
  resourceType: 'node--article',
  config: { mode: 'teaser', schemaType: 'view' },
  fields: {
    field_image: {
      id: 'field_image',
      type: 'image',          // the Drupal field formatter id
      weight: 0,
      label: { text: 'Image', position: 'hidden' },
      settings: { /* formatter settings */ },
    },
    // ...
  },
}

Each field entry has the formatter and its settings from Drupal, in weight order. Entity components turn each field's formatter type into a DruxtField* component (an image formatter becomes DruxtFieldImage), so the field order and configuration in the schema is what renders on the page.

Where schemas come from

DruxtSchema reads Drupal's entity_view_display and entity_form_display config entities over JSON:API: the same entities that power Drupal's own Manage display screens. A schema is assembled per combination of entity type, bundle, display mode, and (where relevant) form or view variant, then cached in its own Vuex store.

A site builder rearranging fields in Drupal changes the decoupled frontend too, since both read the same source of truth.

Schemas are generated once, at startup

druxt-schema builds every schema during Nuxt's builder:prepared hook (once, when nuxt dev or nuxt build starts) and writes each one to a static schemas/<id>.json file. At runtime, $druxtSchema.import(id) reads that file. There is no live JSON:API request for schemas after startup.

In practice, this means rearranging fields, changing a formatter, or adding a new view mode in Drupal will not appear on the frontend until you restart nuxt dev (or rebuild). This surprises people because content changes update live but display-mode changes don't: they run through entirely different paths.

Schemas shape the queries, not just the rendering

A less visible role: schemas narrow the JSON:API query. Rendering only needs the fields the display includes, so the fetch can add a fields[node--article]=... filter derived from the schema. Less data crosses the wire, and because the store distinguishes partial from full resources, those slim fetches cache as partial, not as complete resources.

The entity module enables this with:

druxt: {
  entity: {
    query: { schema: true },
  },
},

Field components

Rendering a field means choosing a component for its formatter. The schema system maps Drupal field formatters to DruxtField* components: an image field with an image formatter becomes DruxtFieldImage, a text field with the default formatter becomes DruxtFieldTextDefault, and so on. As with everything Druxt, the chosen component is then themeable via the suggestion system: you override the rendering, not the mapping.

Why display modes?

The alternative designs all have a known failure mode: a parallel frontend field configuration drifts from Drupal, or a bespoke "fields in YAML" format reinvents what site builders already manage. Display modes come with a UI, per-bundle and per-mode overrides, third-party settings from contrib, and a decade of Drupal muscle memory. Druxt inherits all of it, at the cost of depending on display-mode config being present and correct on the backend.

Where to go next