Writing diagrams by hand with a mouse gets messy fast. Boxes drift out of alignment. Arrows point the wrong way. And when the architecture changes which it always does you start over from scratch. Diagram markup languages solve this by letting you describe diagrams as plain text code, the same way you write HTML for web pages. If you work with software architecture, system design, DevOps pipelines, or technical documentation, learning how to write diagram code using markup languages saves hours of manual drawing and produces consistent, version-controlled results every time.

What does it mean to write diagrams with markup code?

A diagram markup language is a text-based syntax that describes the structure and relationships in a diagram. Instead of dragging shapes onto a canvas, you write short lines of code that declare nodes, connections, and labels. A rendering engine then converts that code into a visual diagram usually a PNG, SVG, or PDF file.

The idea is similar to how Markdown converts plain text into formatted documents. You write what the diagram should contain, and the tool handles how it looks. This approach is sometimes called "diagram-as-code" or "text-based diagramming."

Why not just use a drawing tool?

Drawing tools like Lucidchart, Draw.io, or PowerPoint work fine for quick one-off visuals. But they have real limitations once your diagrams need to live alongside code:

  • No version control. Binary files like .pptx or .drawio don't diff well in Git. You can't see what changed between commits.
  • Manual layout work. Every time you add a component, you rearrange everything by hand.
  • Hard to reuse. Copying a diagram into another document often breaks formatting.
  • Collaboration friction. Two people can't easily edit the same diagram file at the same time without a paid platform.

With markup-based diagrams, the source is a plain text file. You can store it in a Git repo, review changes in pull requests, generate diagrams in CI/CD pipelines, and embed them in documentation sites. The syntax differences between diagram markup languages are worth comparing before you pick one, since each language has a different learning curve and feature set.

Which markup languages can you use for diagrams?

Several open-source markup languages are widely used today. Here are the ones you're most likely to encounter:

  • PlantUML Supports sequence diagrams, class diagrams, use case diagrams, activity diagrams, state diagrams, and more. Uses a Java-based renderer. One of the most mature options with a large community.
  • Mermaid Built into GitHub, GitLab, and many documentation tools. Renders in the browser using JavaScript. Supports flowcharts, sequence diagrams, Gantt charts, and class diagrams.
  • D2 A newer language focused on readability and automatic layout. Designed for DevOps and infrastructure diagrams.
  • Graphviz (DOT language) One of the oldest text-to-diagram tools. Strong at directed and undirected graphs. Often used in academic and technical contexts.
  • Structurizr DSL Built specifically for the C4 model of software architecture. Good for documenting systems at multiple zoom levels.

Each language has its own strengths. PlantUML and Mermaid are the most common starting points for software teams because of their broad diagram type support and integration with existing tools.

How do you write your first diagram in markup code?

Let's walk through a basic example. Say you want to draw a simple flowchart showing a user logging into an application. Here's what that looks like in Mermaid:

graph TD
  A[User opens app] --> B{Has account?}
  B -->|Yes| C[Enter credentials]
  B -->|No| D[Sign up]
  C --> E[Validate login]
  D --> E
  E --> F[Dashboard]

The same diagram in PlantUML would look like this:

@startuml
start
:User opens app;
if (Has account?) then (yes)
  :Enter credentials;
else (no)
  :Sign up;
endif
:Validate login;
:Dashboard;
stop
@enduml

Both produce the same visual result a flowchart with decision branching. The syntax differs, but the pattern is the same: declare nodes, connect them with arrows, and let the renderer handle layout.

What does a real-world architecture diagram look like in code?

Suppose you're documenting a microservices setup with an API gateway, three services, and a shared database. In PlantUML, the code might look like this:

@startuml
component "API Gateway" as gateway
component "User Service" as users
component "Order Service" as orders
component "Payment Service" as payments
database "PostgreSQL" as db

gateway --> users
gateway --> orders
gateway --> payments
users --> db
orders --> db
payments --> db
@enduml

This produces a clean component diagram with six elements and six connections. If you later add a message queue or split the database, you just edit the text no redrawing required. For a deeper walkthrough of microservices diagrams, see this guide to writing microservices diagram code in PlantUML.

What are the most common mistakes when writing diagram code?

Beginners (and experienced developers) run into the same problems repeatedly:

  • Trying to do too much in one diagram. A single diagram showing your entire system with 40 services is unreadable. Break it into smaller, focused views one per subsystem or flow.
  • Skipping labels on connections. Arrows without descriptions leave readers guessing about the nature of the relationship. Is it a synchronous call? An async message? A data flow? Label it.
  • Ignoring the renderer's layout rules. Each markup language has its own auto-layout algorithm. If you fight it (for example, by forcing too many crossing connections), the output looks tangled. Structure your code to minimize crossings.
  • Not testing output in the actual rendering tool. Code that parses correctly can still produce a confusing visual. Always render and review before committing.
  • Leaving diagram source files out of version control. The whole point of text-based diagrams is traceability. Store .puml, .mmd, or .d2 files in the same repo as your code.

How can you write cleaner, more maintainable diagram code?

A few habits make a big difference over time:

  • Use aliases and variables. PlantUML lets you alias long component names. Mermaid supports subgraph grouping. Use these features to keep your code readable.
  • One diagram per file. Don't mix unrelated diagrams in a single source file. It makes diffs harder to review.
  • Add comments. Just like regular code, diagram code benefits from explaining why something is structured a certain way.
  • Follow a naming convention. Use consistent, descriptive names for nodes. user-service beats us1.
  • Automate rendering. Set up your CI pipeline to generate diagram images from source files on every commit. Tools like PlantUML's Docker image or Mermaid CLI make this straightforward.
  • Embed diagrams in docs. If you use MkDocs, Docusaurus, or a wiki that supports Mermaid, embed the diagram source directly so it stays in sync with the codebase.

When comparing different approaches, this syntax comparison across diagram markup languages can help you decide which tool fits your team's workflow best.

Where can you practice writing diagram code?

You don't need to install anything to start. These online editors let you write and preview diagram code in your browser:

GitHub and GitLab both render Mermaid diagrams natively in Markdown files and pull request descriptions, so you can start using diagram code in your actual workflow without extra tooling.

Practical checklist: your first markup-based diagram

  1. Pick a language. Start with Mermaid if you want quick browser rendering, or PlantUML if you need more diagram types.
  2. Open an online editor. Use the live editors linked above to experiment without installing anything.
  3. Write a simple diagram. Start with three to five nodes and a few connections. A login flow or basic system overview works well.
  4. Render and review. Check the output for readability. Adjust node order in your code if the layout looks tangled.
  5. Save the source file. Commit it to your repo alongside the documentation it describes.
  6. Automate if it sticks. Once your team adopts the practice, add diagram rendering to your CI pipeline or docs build process.

Start small. One well-maintained diagram-as-code file in your repo is worth more than ten screenshots nobody keeps updated.