12k
All articles

How to Control Diagram Layout in Mermaid

Control Mermaid 12 diagram layout with ELK or dagre. Set global and per-diagram options, tune ELK, and restore pre-12 rendering when upgrades change diagrams.

OpenReplay Team
OpenReplay Team
How to Control Diagram Layout in Mermaid

In Mermaid 12, the layout config key decides the layout engine: ELK is the default for most graph diagrams, and you set layout: dagre in front matter or mermaid.initialize() to get the previous engine back.

You upgraded, rebuilt the docs site, and a flowchart nobody has touched now has a different shape and different colours. A diagram type section like flowchart: { defaultRenderer: ... } from an older answer won’t fix it.

This article covers what changed, where to set the layout, which setting takes priority, how to tune ELK, and why a revert can appear to do nothing. For flowchart basics, see creating flowcharts for workflows.

Key Takeaways

  • Since Mermaid 12.0.0, flowchart, state, class, entity relationship, requirement, use case and agentflow diagrams that don’t set a layout are arranged by ELK instead of dagre.
  • layout: dagre brings back the old arrangement but not the old appearance. The full pre-12 rendering needs layout: dagre, theme: default and look: classic.
  • Front matter or a directive on a diagram overrides mermaid.initialize(), so a site-wide dagre setting does nothing for a diagram that picks its own layout.
  • defaultRenderer was removed from the flowchart, class and state config sections in Mermaid 12. Use the top-level layout key instead.
  • The tiny build doesn’t include ELK and falls back to dagre unless you add @mermaid-js/layout-elk.

What Changed in Mermaid 12?

Starting with Mermaid 12, a diagram that doesn’t specify a layout is arranged by ELK instead of dagre. That means an unchanged diagram can come out a different shape after you upgrade. The Layouts configuration page lists seven diagram types that now default to ELK: flowchart, state, class, entity relationship, requirement, use case and agentflow. ELK ships with the main package and registers itself automatically. Mindmaps still use cose-bilkent by default, and tidy-tree comes from the separate @mermaid-js/layout-tidy-tree package.

The mermaid@12.0.0 release notes also describe a second change. The default theme is now redux-color and the default look is now neo, for the wider set of diagram types listed in the theming page’s per-diagram defaults. So a v12 diagram can look different for two separate reasons: the layout engine changed, and the theme and look changed.

Where Do You Set the Layout: Front Matter, initialize() or Per-Type Config?

You can set the Mermaid layout on one diagram or for every diagram on a site. You can also scope theme and look to a single diagram type. When settings conflict, the most specific one wins.

ScopeWhereSyntaxBeats
One diagramFront matter or directiveconfig: layout: dagreEverything below
All diagramsmermaid.initialize() top level{ layout: 'dagre' }Type and global defaults
One diagram typeBuilt-in type default(set by Mermaid)Global default
EverythingGlobal default(set by Mermaid)Nothing

The 12.0.0 release notes give the resolution order as: front matter or directive first, then initialize(), then the diagram type’s default, then the global default.

Here is how to revert a single diagram completely:

---
config:
  layout: dagre
  theme: default
  look: classic
---
flowchart LR
  Request --> Auth{Valid token?}
  Auth -->|yes| Handler
  Auth -->|no| Reject

Site-wide, the first call below changes the engine and nothing else, so the new colours stay. The second call brings back the whole pre-12 rendering:

mermaid.initialize({ layout: 'dagre' });

mermaid.initialize({ layout: 'dagre', theme: 'default', look: 'classic' });

Mermaid 12 also lets you scope theme, look and layout to one diagram type, inside that type’s config section. A scoped value beats a global one set in the same place. To switch every diagram to dagre but bring back the old appearance for class diagrams only, keep layout at the top level and put theme and look in the class section, as the class diagram page shows:

mermaid.initialize({
  layout: 'dagre',
  class: { theme: 'default', look: 'classic' },
});

Front matter always beats mermaid.initialize(). Suppose a site sets layout: 'dagre' site-wide and one diagram declares layout: elk in its front matter. That diagram renders with ELK.

When Does the Mermaid ELK Layout Help and How Do You Tune It?

Use ELK for large or crowded diagrams. Keep dagre when a small diagram already looks fine. The Mermaid docs pitch ELK for big, intricate graphs, and dagre is still available as the long-standing layered layout. If your diagrams rendered well before the upgrade, reverting to dagre is a reasonable choice.

The syntax reference’s layout section documents several ELK tuning keys, including these. mergeEdges combines parallel edges. nodePlacementStrategy accepts SIMPLE, NETWORK_SIMPLEX, LINEAR_SEGMENTS or BRANDES_KOEPF, and BRANDES_KOEPF is the default under the default preset. nodePlacementAlignment sets the Brandes-Koepf alignment (for example BALANCED or NONE). When you leave it out, the alignment comes from the preset.

---
config:
  layout: elk
  elk:
    mergeEdges: true
    nodePlacementStrategy: NETWORK_SIMPLEX
---
flowchart TD
  Build --> Test --> Deploy
  Build --> Lint --> Deploy

Diagrams that already used ELK before v12 can change too, because balanced Brandes-Koepf placement is now the default. The ELK preset schema lists four preset values: legacy, default, modelOrder and depthFirst. It describes depthFirst as the previous default and says legacy reproduces how ELK rendered before presets existed.

ELK output has also changed within 12.x:

  • Mermaid 12.1.0 added orientFeedbackEdges, which is on by default. An edge running from a node that a subgraph feeds back into that subgraph is now routed downstream instead of around the subgraph.
  • Mermaid 12.2.0 stopped ELK from straightening an edge terminal when doing so would put a label over another edge.
config:
  layout: elk
  elk:
    preset: legacy
    orientFeedbackEdges: false

Which ELK Variants and Per-Subgraph Algorithms Can You Use?

Besides layout: elk, the Mermaid Layouts page lists six ELK variants you can use as layout values: elk.stress, elk.force, elk.mrtree, elk.sporeOverlap, elk.box and elk.rectpacking.

---
config:
  layout: elk.mrtree
---
flowchart TD
  Root --> API
  Root --> Web
  API --> Workers

According to the 12.0.0 release notes, elk.box and elk.rectpacking place nodes but don’t route edges, so their edges are drawn as straight lines from centre to centre.

A single subgraph can choose its own algorithm with @{ algorithm: ... }. The same release notes list the accepted values as the six variants plus elk.layered and elk.radial. They also say two things about this override: Mermaid ignores unsupported values with a warning, and it uses the inherited algorithm instead whenever edges cross the subgraph’s boundary.

Why Isn’t My Layout Fix Working?

Most failed reverts come from one of five causes. Check them in this order:

  1. You still set defaultRenderer. The flowchart syntax page notes that it was removed from the flowchart, class and state sections in v12. Use layout instead.
  2. You set only layout: dagre. The redux-color theme and neo look are still active. Set all three keys.
  3. Front matter overrides your initialize(). Remove layout from that diagram’s front matter.
  4. A layout name is misspelled or unregistered. The release notes say Mermaid falls back to dagre with a warning instead of throwing an error. Check the console.
  5. You’re on the tiny build. See the next section.

Moving off defaultRenderer is a one-line change:

// Before (removed in v12)
mermaid.initialize({ flowchart: { defaultRenderer: 'elk' } });

// After
mermaid.initialize({ layout: 'elk' });

If your docs platform hasn’t moved to v12 yet, these keys may still behave the old way. Check the platform’s own documentation.

Why Does the Tiny Build Fall Back to dagre?

The tiny build of Mermaid leaves ELK out, so any diagram that asks for ELK there renders with dagre. The @mermaid-js/layout-elk package is still published for this case. Follow the registration steps in the ELK and the tiny build section of the usage docs. On the normal build, existing registerLayoutLoaders calls keep working but are no longer needed, and you can delete them.

Conclusion

A diagram that changed after the Mermaid 12 upgrade almost always has two causes: the ELK layout engine and the new theme and look. Decide what you want back. If you only want the old shapes, set layout: dagre. For the full pre-12 rendering, set layout: dagre, theme: default and look: classic. Then search your config for any leftover defaultRenderer settings and any front matter that overrides your site-wide choice.

FAQs

Does the flowchart-elk diagram keyword still work in Mermaid 12?

Yes. The Mermaid 12.0.0 release notes say flowchart-elk still works as an explicit diagram keyword. The defaultRenderer option is the part that changed. Mermaid ignores it rather than rejecting it, so a config that still sets it throws no error but has no effect. A diagram that relied on a flowchart defaultRenderer value of 'elk' for its ELK layout should set layout: elk instead.

Does bundling ELK make Mermaid 12 larger to load?

Only the single-file build grows noticeably. In the ESM builds, ELK is a separate chunk that loads only when a diagram uses it. The 12.0.0 release notes say the IIFE build, mermaid.min.js, inlines ELK and grows by roughly 500 kB gzipped. The tiny build leaves ELK out, stays the same size, and lays out ELK requests with dagre.

Can I set ELK tuning options site-wide instead of in each diagram's front matter?

Yes. elk is a top-level property in the Mermaid config schema, so you can pass it to mermaid.initialize() next to layout, for example layout: 'elk' with an elk object containing mergeEdges: true and nodePlacementStrategy: 'NETWORK_SIMPLEX'. A %%{init}%% directive accepts the same elk object for one diagram. Front matter on an individual diagram still overrides the site-wide values.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.