Flow in a large org: conventions that hold at a hundred flows
Advice that works at ten flows actively fails at a hundred, because at a hundred nobody can hold the estate in their head and every convention has to survive being read by someone who was not there.
Platform & ArchitectureA flow estate does not fail on the day it becomes unmanageable. It fails about a year earlier, when the last person who could describe the whole thing stopped being able to, and nobody noticed, because everything still ran.
Most published Flow advice is written for the org where that person still exists. It assumes a reader who can open the list of flows, recognise every entry and reason about what fires when. At a hundred flows, built by two partners and three generations of internal admin, that reader exists nowhere in the organisation, and every convention that quietly depended on them stops working without announcing it.
The conventions below survive that transition. The test each has to pass is not whether an architect agrees with it, but whether a competent person who was not in the room can apply it from what is written in the org.
What actually changes between ten flows and a hundred
Three things, and none is complexity in the ordinary sense.
Reading replaces remembering. At ten flows the fastest way to answer what updates this field is to ask somebody. At a hundred it is to search, and search only works if the thing was named by someone who anticipated the search.
Blast radius stops being knowable by inspection. A change to a subflow used in nine places is a change to nine processes, and the person making it can see the subflow but not the nine. Reuse, unambiguously good at small scale, becomes a risk surface needing an owner.
Nothing is ever deleted. In a large org removal means proving a negative in front of people who will be blamed if the proof is wrong, so the rational move is to deactivate and walk away. The estate stops being a set of things that run and becomes a set of things, some of which run.
Every convention worth writing down addresses one of those three. Anything else is style preference, and style preference does not survive a deadline.
Naming is the index, and there is no other one
The flow list is the only navigable surface an admin has over the estate, and it is a list of names. Whatever a name does not say has to be discovered by opening the flow.
A name that works at scale encodes what it acts on, what triggers it and what it is for, in that order, because the list sorts alphabetically and you want it clustering by object. Opportunity, then before-save, then derive discount band, gives a reader object, timing and purpose before they open anything. Discount Update v2 Final gives them nothing, and costs an hour every time somebody works out whether it is the live one.
Set the name at creation, do not correct it at review. Reviews get skipped under deadline and nobody goes back to rename. Put the convention in the build template, the ticket and the definition of done, where complying costs nothing.
Keep version numbers out of names. The platform already versions flows. A name carrying v2 or New or Final describes build history, which stops being interesting the moment the build is done, while the name stays for years.
One record-triggered flow per object, and the honest case against it
Keeping one record-triggered flow per object, per timing, is close to consensus and we give it to most teams. It deserves the argument rather than the assertion, because at a hundred flows the counter-argument is real.
The case for it is ordering. Multiple flows at the same timing run in a sequence you did not choose unless trigger order is set explicitly, and even then that order becomes a dependency somebody maintains. Consolidating removes a class of failure that is hard to reproduce and harder to explain to a change board.
The case against it is usually left out. A single flow centralises risk: everything touching Opportunity on save lives in one artefact, so a bad deployment breaks all of it rather than one process. It also makes concurrent work painful, because two people cannot comfortably edit one flow and flow metadata does not merge in any way a human wants to review. A busy object becomes a queue.
Consolidate by default, then split when a named condition is met. The conditions worth splitting on are ownership and release cadence, not size: forcing two teams on different release schedules into one artefact converts a design problem into a coordination problem, and coordination problems cost more than an ordering rule does. The wider pattern catalogue sits on Salesforce Architects.
A split carries an explicit ordering, written down at the time. The rule is not one flow. It is that the number of flows on an object is something somebody chose and can defend.
Entry criteria, because a flow that exits immediately still ran
An underrated cost in a large estate is automation that does nothing. A record-triggered flow with no entry conditions is evaluated on every save of that object, and when its first decision element routes it straight to the end, the transaction has still paid for considering it.
At ten flows this is invisible. At a hundred, on an object written to by an integration, a nightly job and several hundred users, it is a share of a transaction budget shared with every trigger, managed package and flow on the same save. The per-transaction limits on queries, DML and processing time are communal rather than allocated per automation, and their values move between releases, so check current Salesforce developer documentation rather than a remembered figure.
Put the condition in the entry criteria, not the first decision element. Entry criteria are evaluated before the flow is entered at all. A decision element is evaluated after everything the flow did to reach it.
State the condition as what changed, not what the record looks like. A condition describing current state fires on every save leaving the record in that state, including saves unrelated to your process. A condition describing a change fires when the thing you care about happened, and that removes most accidental re-entry.
Ordering, and why implicit order is a defect waiting for a release
Wherever more than one automation runs on the same object and timing, an order exists. The only question is whether it is one you chose.
Order that was never set explicitly is a property of the platform at the version you happened to test on. It may hold for a long time, which is what makes it dangerous: the org accumulates logic depending on it, nobody records the dependency, and the failure surfaces in a release window with no obvious cause.
Make the dependency visible in both directions. Where a flow relies on another having run first, that expectation belongs in writing on both, because the person who breaks it will be working on the other. Where trigger order values are set, they belong in the standard, since a number set once and never documented is indistinguishable from a default.
Better still, remove the dependency rather than record it. Logic reading a value another automation has just written is fragile in a way that logic deriving the value itself is not.
Subflows for shared logic, and why copy-paste keeps winning
Reuse is the default recommendation and copy-paste is the default behaviour. It is worth understanding why the behaviour wins, because the answer is not laziness.
A subflow used in nine places has nine callers, and the person changing it can see none of them from inside it. In an org with no automated coverage over declarative automation, which is most orgs, that person is accepting unbounded risk for a change that would be trivial in a copy. Choosing the copy is rational for anyone accountable for not breaking things.
So the rule is not prefer subflows. It is that a subflow is justified only when somebody owns it, and ownership means something specific: a named role consulted before it changes, a written statement of what it guarantees callers, and a caller list maintained rather than reconstructed under pressure.
Without that, duplicated logic is safer. Its cost, drift between copies, is visible and slow, while an unowned shared component fails invisibly and everywhere at once.
Reserve subflows for logic that is genuinely one thing rather than several similar things: address standardisation, an approval routing rule, a scoring calculation somebody in the business owns. If two callers would pull it in different directions within a year, it was never shared logic. It was two things that looked alike.
Documentation that lives where the flow lives
Every large org has a wiki page describing its automation and almost none are current. The reason is structural: the documentation sits somewhere the person making the change does not have to go.
Put the record where the work happens. The flow description field is the highest-value real estate in the estate, because it shows in the list view and cannot be missed when editing. Four lines is enough.
WHY. The business reason and its source: a ticket, a policy, a named approval, a date.
OWNER. The role accountable, and where escalation goes.
SCOPE. What it acts on, and explicitly what it does not, because the second half prevents the duplicate.
RISK. What else runs on this object at this timing, and what a change here can break.
Name every element for a reader while you are in there. A step called get open renewal opportunities is a sentence. A step left as Get Records 3 is an artefact of the order somebody dragged things onto a canvas, and it leaves the flow readable only by its author.
A deprecation path, because switched off is not gone
Large orgs accumulate deactivated automation faster than active automation. Every inherited estate has flows switched off years ago by people who have since left, kept because deleting felt riskier than not deleting, which it always does in the moment.
The cost is not runtime. It is that every future audit, every impact analysis and every new admin works out again, from scratch, which of these things still matter, and reaches the same inconclusive answer.
Three rules turn removal into a process with a defined end rather than a decision somebody has to be brave about.
Deactivate with a stated window and a named watcher. Not switch it off and see. Switch it off, on a date, with a person who will notice, for a period agreed in advance.
Book the deletion at the moment of deactivation. An indefinite deactivation is how the graveyard got its population.
Record the reason where the flow was documented. The next person finds a decision rather than an absence, and does not rebuild the same logic under a new name.
That converts an argument about risk into an experiment with a deadline, which is what makes retirement politically possible, because nobody has to be proven wrong for a flow to go.
The standard, in one table
This is the version we hand teams. It is short enough to adopt without a project, and the third column is the one that gets it approved.
| Convention | The standard | What it prevents |
|---|---|---|
| Flow naming | Object, then trigger and timing, then purpose. No version numbers. | Flows nobody can find, and duplicates built because the original was invisible |
| Flows per object | One record-triggered flow per object per timing by default | Ordering dependencies nobody chose |
| Splitting rule | Split on ownership or release cadence, never on size | One artefact queued behind two teams on different schedules |
| Entry criteria | In the entry criteria, expressed as what changed | Flows that run and exit, and re-entry on unrelated saves |
| Ordering | Explicit wherever a dependency exists, recorded on both flows | Failures that surface at a release with no cause and no owner |
| Subflows | Only where a named owner, a stated contract and a caller list exist | Shared components that break nine processes at once |
| Element naming | Elements named as a sentence, never by type and number | An estate readable only by whoever built it |
| Description field | Why, owner, scope, risk. Four lines, written at build time. | Logic nobody can retire because nobody can justify retiring it |
| Deprecation | Deactivate with a window and a watcher, delete on a booked date | A graveyard every future audit pays to walk through |
| Ownership | Every flow has an accountable role, not an accountable person | Orphans created on the day somebody leaves |
The last row does the most work. Roles rather than individuals, for the same reason large organisations write runbooks: the convention has to survive the org chart changing, and it will change several times before the flows do. Ownership recorded as a person is a countdown.
Where to start on an estate you already have
Nobody reads this with an empty org, so the useful version is an audit rather than a design method.
List every record-triggered flow by object and timing. Wherever more than one appears at the same timing you have an ordering dependency you did not choose, and that list is the work queue in priority order. Then read the entry criteria on your busiest objects, looking for conditions describing a state rather than a change. Then put a date against every deactivated flow: delete, or keep with a written reason. Then take the three flows nobody can explain and either write the WHY line or agree to retire them.
None of that needs a budget, a migration or a new tool on the platform. It needs somebody with the standing to say that a flow without an owner is not finished.
The prior question, what belongs in Flow at all, we argue in Flow or Apex? Write the decision down before you build. The same accumulation problem shows up on the access side, quieter and more expensive, in permission set debt. And the principles that keep automation something people cooperate with rather than route around are in Sales Cloud automation that reps do not work around.
Conventions like these look like bureaucracy at ten flows and like infrastructure at a hundred. The uncomfortable part is adopting them while they still look like bureaucracy, because the transition arrives without an announcement, and the first sign of it is a question nobody in the room can answer.



