Draw a system architecture diagram from your code
A system architecture diagram shows the parts of a system and how they depend on each other. Derive it from the code, its modules, imports and entry points, and it stays true far longer than one drawn from memory.
What is a system architecture diagram?
A system architecture diagram is a picture of a system's main parts, such as services, modules, stores and outside systems, and the connections between them. A software architecture diagram is the same idea seen from inside the code: packages, layers and which one imports which. A high-level architecture diagram keeps only the few boxes a newcomer needs on the first day.
Almost every team has an architecture diagram, and almost every team has one that is wrong. It was accurate on the day it was drawn. Then a service was split, a queue was added, a module was deleted, and nobody reopened the file. Six months later a new engineer trusts it and loses an afternoon.
Why hand-drawn architecture diagrams drift
A drawing has no connection to the code it describes. Nothing fails when the two disagree, so the drawing is updated only when someone remembers, and people remember when they are not busy, which is rarely. There is a second cause: diagrams are drawn from the author's mental model, and that model is already an abstraction. Two people asked to draw the same system will draw different boxes.
The fix is not discipline. It is to derive the diagram from something that cannot drift silently, which is the code.
What the code can tell you
Source code contains a lot of structure that a diagram needs:
- Modules and packages, from the folder layout.
- Dependencies between them, from import statements. If
billingimportsaccountsand never the reverse, that arrow is a fact. - Entry points, from manifests and main modules: servers, command-line tools, workers.
- External systems, from client libraries, connection settings and configuration: a database driver, an HTTP client for a payment provider, a message queue.
- Data flow, partly: you can follow a value from where it enters a function to where it is stored or returned.
What the code cannot tell you
Be honest about the limits, because a confident wrong diagram is worse than none.
- Runtime topology. Code does not say how many replicas run, where they are deployed or which load balancer sits in front. Infrastructure files such as a
Dockerfile, a Terraform module or a Kubernetes manifest help, but they describe intent, not what is running today. - Intent and ownership. Why a boundary exists, which team owns it, which service is being retired: this lives in people's heads and in tickets.
- Dynamic wiring. Plugins loaded by name, dependency injection from configuration and calls made through reflection do not show up in a static read of imports.
A good diagram says what it was derived from and leaves these gaps visible instead of guessing.
Two views that earn their place
The module view, the usual software architecture diagram, answers "what are the parts and who depends on whom?" Draw one box per top-level module or package, and one arrow per real import direction. Keep it to a dozen boxes; group the rest. This is the diagram a new engineer needs on the first day.
The data-flow view answers "what happens to a request?" Pick one important path, such as an upload, a payment or a job run, and draw the stages in order with the stores they touch. Sequence diagrams and flowcharts both work. One path per diagram keeps it readable.
Resist the diagram of everything. Each diagram should answer one question that you can write as its title.
Choosing an architecture diagram tool
Diagrams written as text, such as Mermaid or PlantUML, live in the repository, show up in code review and can be regenerated. Diagrams drawn in a visual tool are easier to polish and present. The practical answer is to be able to move between them. Tools like draw.io open an editable file, so a diagram can be generated first and then adjusted by hand for a slide or a design review.
When you compare architecture diagram tools, ask three questions. Does it start from the code, or from a blank canvas? Can the result live in the repository as text? Can you still edit it by hand afterwards?
Whatever you choose, check the diagram against the code the way you check any claim. Pick three arrows and find the import or the call that justifies each one.
How Nehemvix does it
Nehemvix draws two diagrams for a guide. The building-blocks view comes from its reading of the repository: each box has a kind (an external system, an entry point, a component, a package, a data store, configuration, tooling, tests or docs) shown by its shape and colour and explained in a legend, related boxes sit in labelled groups, and a box shows its folder or file only when that path exists. The folder-dependency view is counted from the real imports, with test and example folders folded together and only the strongest links drawn. Both are kept as Mermaid text inside the guide, laid out by Graphviz with labels on their own arrows and never cut mid-word, and the check that runs on every guide confirms that each diagram is present and well formed. Every diagram can be exported as an editable draw.io file, with its groups, shapes and legend, so you can restyle it or merge it into your own documentation. The file and module names in the text around a diagram are looked up in the real code, and anything it could not find is listed. It cannot see how your system is deployed, so treat the runtime picture as something to add yourself.
See how Nehemvix works for the whole pipeline and the export options in the documentation.
Related reading: How to understand a new codebase, How to document a LangGraph project and, for how two code-to-documentation tools differ, Nehemvix vs DeepWiki.
Learning this to build your own agent? AELSHA™ can help you design it.