A schematic diagram creator, in the sense of a system sketch you can keep in git, is a text grid. You decide the rows, you put one kind of thing on each row, and you add an arrow only where the row order doesn't already tell the story. This is not an electrical CAD tool. There are no resistor symbols, no pin numbers, and no claim that a box is a chip. It is a system schematic: clients, an edge, services, and the data under them. The picture stays where you put it because you set the columns, which is the part a flowchart will not promise you.
A schematic is a layout
I use the word schematic for a drawing whose positions mean something. The top row is what a person touches. The middle row is what your process runs. The bottom row is what you will restore from a backup. If a box drifts to the wrong row, the drawing is wrong even when every arrow is still true. That is a different failure mode from a flowchart, where the engine is allowed to move a box as long as the edges survive.
block-beta is the Mermaid form that gives you that control. columns 3 means three cells across. A block can span with :3 so a band occupies the whole row. The id stays short. The label is what the reader sees. browser["Browser"] is an id of browser and a label of Browser. Arrows point at ids. If you rename the label and leave the id, the arrows keep working. If you rename the id because you were editing the only word you could see, the arrows dangle and the preview complains. I learned that by doing it twice.
The block diagram syntax page documents columns, spans, and arrows. This post is the how-to for using them as a system schematic. A separate page, text to schematic diagram, is about turning a description into that picture. I am not repeating it. Here the assumption is you already know the boxes and you want them to sit in rows you can defend in review.
A flowchart is the wrong creator for this job, and I say that as someone who reaches for flowchart TD first out of habit. Flowcharts are excellent at decisions. They are unreliable at "this row is the data tier." Add one more service and the database can slide up next to the browser. The logic is fine. The schematic is ruined. When the row is the meaning, I switch to blocks and I stop apologizing for the plainer picture.
Rows I am willing to explain
I use four bands, and I delete any band I can't name in review.
The client band is who sends the request. Browser, mobile app, a partner calling your API. If a box in this band is actually a backend service, you have flattered someone. Move it down.
The edge band is the thing in front of your code: a CDN, a proxy, a WAF. It spans the row because it is a layer, not a sibling of the API. A span of :3 on a three-column grid is the whole point. If you leave it as one cell, it looks like a service that happens to sit on the left, and people will ask what the empty cells are for.
The service band is processes you deploy. Web, API, worker. Three boxes, one each, because they scale and fail separately. If two of them are the same binary, draw one box. A schematic that splits a process to look busy is how incident calls go wrong. Someone restarts "web" and the worker was the same pod.
The data band is state. Postgres spans two columns when it is the system of record and a cache sits in the remaining cell. The span is a claim about importance, so don't span a cache just because the label is long. Widen the label's column by giving it a short name. cache["Cache"] fits. cache["Redis cluster with volatile keys for sessions"] does not belong in the cell. Put that sentence under the figure.
The system layers template is a worked grid in this shape. Rename the boxes. Don't add a fifth band for "observability" unless the review is about where metrics go. A schematic that includes every agent you installed last quarter is a catalog. Catalogs are lists.
One grid for a small app
This is the schematic I want on the service README. The browser is a full-width row. Web, API, and worker share the next row. Postgres takes two columns and the cache takes the last. Arrows are the paths I am willing to say out loud. The browser talks to the API. The web app talks to the API. The API and the worker both use Postgres. The API uses the cache. The worker does not get a cache arrow in this picture, because in this system it doesn't have one.
block-beta
columns 3
browser["Browser"]:3
web["Web"]
api["API"]
worker["Worker"]
pg["Postgres"]:2
cache["Cache"]
browser --> api
web --> api
api --> pg
worker --> pg
api --> cacheCount the cells before you trust the picture. Row one is a span of 3, which fills columns 3. Row two is three blocks of span 1. Row three is a span of 2 plus a span of 1. If those numbers don't add to 3, Mermaid wraps and the cache sits next to the browser. That wrap is the most common broken schematic I see, and it looks almost plausible. The cache didn't grow a user interface. The arithmetic failed.
browser --> api crosses two rows. That is allowed. It is also a claim that the browser does not call Postgres. If a debugging console in the marketing site talks to the database, this schematic is a lie and you should add the arrow or delete the console. I prefer the delete. A schematic that grows an arrow for every shortcut becomes a flowchart drawn badly on a grid.
The worker points only at Postgres. If the worker's real job is to drain a queue, the queue is missing and the picture is too calm. Add a block only when you can say which row it occupies. A queue is data, so it belongs on the bottom row, which means the bottom row has to be redesigned. Maybe columns 4, or the cache and the queue share the row and Postgres spans less. Do the arithmetic on paper first. I have "fixed" this by inserting a block and then spent ten minutes wondering why Web dropped to the data row. The column count was still 3. The new block consumed a cell. Spans are not magic. They are addition.
The decision the grid leaves out
A schematic does not show a branch. The API either is a box or it isn't. The request that gets rejected at the edge doesn't fit in a cell, because both outcomes are the same box. That story is a flowchart, and it should live under the schematic or in a sibling file, not as extra blocks called "403" and "200".
flowchart TD
req[Request arrives] --> edge{Edge allows it?}
edge -->|No| deny[Return 403]
edge -->|Yes| api[API handles it]
api --> db[(Postgres)]The diamond is the question the grid couldn't ask. deny is a terminal for this picture. I didn't name a node end, because that word closes subgraphs and I don't want a future edit to swallow the file. The cylinder on Postgres is a hint that this box is storage. It is not a promise of a particular database product beyond the label. If you swap engines, change the label. The shape can stay.
Keep this flowchart short. The schematic already named the boxes. The flowchart's job is the branch: allowed or not, and then a write. If you copy every block into the flowchart as a node, you now have two maps, and they will diverge the first time someone adds a worker to one of them. I put the worker only on the schematic. The flowchart is one request path. The worker is not on that path. Leaving it off is correct, not an oversight. Say that in the paragraph so a helpful editor doesn't "complete" the chart.
The architecture diagram syntax is the other place people go when they want a schematic with icons. Groups, a cloud boundary, a server icon, a database icon. Use that when the boundary is a real account or cluster and the icon distinguishes a process from a disk. Use blocks when the row is the meaning and you don't want icon vocabulary in the review. The software architecture guide is how I choose among those pictures: context, one sequence, one data model, and a boxes drawing only when the question repeats. A schematic is that boxes drawing. It is not a substitute for the sequence of the request you just flowcharted.
Labels, spans, and arrows you should delete
Labels are nouns. API is a label. API that does billing and also sends mail is a comment that escaped into the box. If the box does two jobs, you might have two boxes, or you might have one box and a sentence. The sentence is cheaper. I write it under the figure: "The API owns billing. Mail is a library call, not a service." That sentence prevents a Mail block from appearing because someone liked the symmetry of four columns.
Spans are for layers and for the system of record. They are not for emphasis. I have seen a team span the worker across two columns because the worker was "important this quarter." The next reader thought the worker was a tier. Importance is a roadmap fact. Tiers are an architecture fact. Don't spend the span on the roadmap.
Arrows are the first thing I delete when the picture gets hairy. On a one-column stack you often need no arrows at all, because down means "calls the thing below." On a three-column grid the neighbors aren't obvious, so a few arrows earn their place. An arrow between every pair means you were afraid to choose. The grid disappears. If the browser calls the web app and the web app calls the API, draw those two. Don't also draw browser to worker "just in case." Just in case is how a schematic becomes a rumor.
Space is a real block. A space cell holds a hole so the next box lands in the column you mean. I use it when the data row has Postgres on the left and a cache on the right and I want a gap rather than a span. I don't use it to make the picture look designed. Empty cells in a review invite the question "what goes here," and if the answer is nothing, the gap should be rare.
The block-beta examples page is a set of grids you can compare when a span wraps and you want to see a known-good column count. The block diagram generator post is the more general tool writeup. This page stays on the schematic habit: rows mean layers, labels stay short, arrows stay few.
Not a circuit, and not a cloud poster
I need to fence this off because the word schematic also means a circuit. Mermaid will not draw a resistor, a capacitor, a ground symbol, or a pinout. If you need those, you need an electronics tool, and you should not approximate them with rectangles labeled R1. Someone will build the board from the wrong picture. I won't help with that approximation.
Vendor icon sets are a similar temptation. A box labeled S3 is a name. It is not the official mark, and this post is not an AWS icon guide. If the review is specifically about Amazon service choices, the AWS diagrams post is the place to see how far a Mermaid sketch can go and where it should stop. For a system schematic I prefer Postgres and Cache as words. The product name can change in a quarter. The row, "data," changes less often. When the product name matters to the incident, put it in the label and accept the churn.
Color is the other way these pictures rot. A red box for "legacy" feels useful and then the legend lives in someone's head. block-beta can take styles, and I still leave them off until a second reader asks for a distinction the label can't carry. A label that says API legacy is ugly and clear. A red box with a label that says API is pretty and depends on a legend you forgot to write down.
Reviewing the diff
A good schematic diff is boring. A label rename, a span that went from :2 to :3 because you added a column, one new arrow. A bad diff replaces the whole grid because someone re-laid it out by dragging, which you can't do in this format, or because they regenerated it and the model reordered the rows. I reject the regenerated file when the rows move without a reason. Position is the content. A reorder is a behavior change, even if every id is still present.
I keep the source next to the README section that describes the runtime, not in a slide folder. Slides are allowed to be stale. The README is what a new hire reads on day two. If the schematic says the worker writes to Postgres and the worker actually writes to a queue, the new hire will trust the picture and page the wrong person. Fix the block in the same pull request as the queue. That is the entire argument for text. The queue addition is a few lines, and the review can see that the data row changed.
Check the column arithmetic in the pull request description if the diff is hard to see. "columns 3, row spans 3 / 1+1+1 / 2+1" takes one line and saves a reviewer from counting in their head. I started adding that line after a span of 2 and two single blocks wrapped under a three-column grid and we shipped a picture that put the cache on its own row. The code was fine. The picture taught the wrong layout for a month.
When the schematic is stable and the only open question is a branch, stop editing the grid. Add the small flowchart beside it, or link the sequence that already exists. A schematic that grows diamonds has forgotten its job. The grid is the map of parts. The diamond is a policy. They can share a Markdown file. They should not share a diagram type.
Paste the grid into the editor and change columns by one on purpose, just to watch the wrap. Then put it back. Once you have seen a block land in the wrong row, you stop treating the column count as a default. It is the schematic.
Related posts
Frequently asked questions
Is this an electrical schematic tool?
No. It will not draw resistors or PCB symbols. It draws system blocks: clients, services, stores.
When do I switch to an architecture diagram?
When you need a boundary with icons, such as a cloud group around a server and a database. A block grid is for rows. An architecture diagram is for membership.
What is the difference between this page and the text-to-schematic post?
This page is how to design the rows. The other post starts from sentences and encodes them. Same diagram type, different job.