Assigner
Blog / How-to 10 min read

Salesforce Round Robin Flow: Build Round Robin Assignment Without Apex

August 2026 · Assigner

Routing Studio
Assigned

Routed by your rules - illustrative sample
Inbox
Assignees load
Skipped

To build round robin in Salesforce Flow, keep the rotation state in records you can write to, then pick the next owner by reading it. The pattern that holds up is a small custom object with one row per eligible rep and a Last Assigned date-time field on each: a record-triggered Flow gets the active reps sorted by Last Assigned ascending, takes the first one, sets OwnerId to that user, and stamps their Last Assigned to now. Salesforce has no native round robin on any object, and Flow has no rotation element, so the state is yours to build and maintain. The counter-in-a-custom-setting version of this is more commonly published and is the weaker of the two. Here is why, plus the two things that break both versions.

Why there is no round robin element in Flow

Flow decides things by reading fields. Round robin is not a field, it is a memory: who took the last one. Nothing on the incoming lead or case tells you that, so any rotation you build has to store the answer somewhere between records and read it back on the next one. Every native approach to round robin in Salesforce, from the old auto-number trick to the most elaborate Flow, is a different answer to the same question of where that memory lives.

There are three candidate homes for it, and one of them does not work at all.

  • A formula over an auto-number field. The memory is the record sequence itself. No storage needed, and no flexibility either.
  • A counter in a list custom setting. A Next Index number field that the Flow reads, uses, increments, and writes back.
  • A timestamp on an assignee record. One row per rep, each stamped with when they last received something. The next owner is whoever was stamped longest ago.

Custom metadata types are the option that does not work, and it is worth stating plainly because it is where a lot of designs start. Flow can read custom metadata records, but it cannot create or update them. There is no Update Records element that will write to a custom metadata type, which is why third-party invocable actions exist specifically to fill that gap. If your rotation pointer lives in custom metadata, the Flow can read it forever and never move it. Use a list custom setting if you want a counter, because those Flow can write.

The timestamp pattern, step by step

This is the build worth copying. It needs two small custom objects and one Flow, and it degrades gracefully when the team changes, which the counter version does not.

Create a parent object, call it Round_Robin__c, with just a Name and an Is_Active__c checkbox. One record per rotation you want to run: inbound web leads, enterprise trials, tier 2 escalations. Then a child object, Round_Robin_Assignee__c, in a master-detail relationship to it, with a User__c lookup to User, an Is_Active__c checkbox, and a Last_Assigned__c date-time field. One row per person in that rotation.

  1. Start a record-triggered Flow on the object you are routing, set to run when a record is created, or created and updated if you also want re-routing.
  2. Set tight entry conditions. This is the step people skip and then spend a day debugging. If the Flow can re-enter on any later edit, records will rotate again every time somebody touches them.
  3. Get the rotation. A Get Records on Round_Robin__c filtered to the right name and Is_Active__c equals true, storing the first record.
  4. Stop if nothing came back. A Decision element checking the rotation is not null. Without it, a renamed or deactivated rotation fails silently and the record keeps its default owner.
  5. Get the next assignee. A Get Records on Round_Robin_Assignee__c, filtered to that rotation and Is_Active__c equals true, sorted by Last_Assigned__c ascending, storing only the first record. That single sort is the entire rotation logic. Whoever has waited longest is next.
  6. Check again that you got somebody before you write an empty owner onto the record.
  7. Set the owner. Update the triggering record so OwnerId equals the assignee's User__c.
  8. Stamp the assignee. Update Last_Assigned__c on that assignee row to now. If you skip this, the same person receives everything forever, which is the most common way this build fails on its first day.

Null date-times sort first in ascending order, which is a useful property rather than a problem: a brand new assignee row with an empty Last_Assigned__c goes straight to the front of the rotation, so onboarding a rep needs one record and no formula edits.

Why the timestamp beats the counter

The counter version stores a Next Index number and a list of user IDs, then does modulo arithmetic against the number of reps. It works, and it is brittle in exactly the way the old auto-number trick is brittle. Change the number of reps and the index no longer points where you think, so the rotation reshuffles for everybody instead of absorbing one change. Deactivate somebody and their slot keeps drawing records that nobody works. The timestamp version has no index to invalidate: adding a rep is a new row, removing one is unticking a checkbox, and the sort takes care of the rest.

ApproachWhere the rotation state livesAdding or removing a repMain failure mode
Auto-number plus MOD formulaThe record sequence, no storageEdit the formula and every rule entryAbsent reps keep drawing their share
Counter in a list custom settingA Next Index number fieldReshuffles the whole rotationThe index and the rep list drift out of step
Counter in custom metadataNowhere, Flow cannot write itNot applicableThe pointer never moves at all
Timestamp on assignee recordsA date-time per repOne row, or untick a checkboxDistributes count, not workload

Chaining it to a queue, which is what most orgs actually want

The cleanest production shape is not one Flow doing everything. It is assignment rules deciding which team, and the Flow deciding which person on that team. Queues are the join between the two.

Point your lead or case assignment rule entries at queues rather than named individuals, then run the round robin Flow with an entry condition of OwnerId starts with 00G. That prefix is the ID prefix for Group records, and every queue is stored as a Group, so that one condition reads as "this record is sitting on a queue and nobody has claimed it". User IDs begin with 005, so the condition never fires on a record that already has a human owner, and the Flow stays out of the way of manual reassignment.

This shape also solves the maintenance problem. Adding a new routing rule is an assignment rule entry, which any admin can make, rather than a branch inside a Flow. If you are designing that layer, Salesforce queue assignment covers which objects can hold a queue, the four ways records get onto one, and the queue email setting that decides who is notified. For the mechanics of writing the owner itself, assigning a record to a queue in Salesforce Flow goes through the Get Records lookup and the before-save versus after-save choice.

The two things that break it

Bulk loads read before they write

Test this before you trust it. A record-triggered Flow processing a batch of records evaluates each one against data as it stands, and the Get Records that picks your next assignee runs before the Update Records that stamps them. Depending on how the batch is processed, several records in one import can therefore see the same rep as least recently assigned. The rotation is not wrong so much as it is granular: it rotates cleanly on the drip of records a web form produces, and it can clump on a five thousand row data import. Load a realistic batch into a sandbox and count the resulting owners before you promise anyone an even split.

It counts records, not work

This is the honest limit of every round robin, native or built. A rotation gives each person the same number of records. It has no idea that one of those records is a password reset and the next is a three week enterprise evaluation, and no idea that one rep is on holiday, in back to back meetings, or already sitting on nine open opportunities. Handling absence in the timestamp pattern means somebody remembering to untick a checkbox, and handling it in the counter pattern means editing a formula. Neither happens reliably on the Friday before someone's vacation.

Teams usually notice this at the point where round robin stops being a fairness mechanism and starts being a source of arguments. Recruiting teams hit it early, because rotating candidates evenly between interviewers ignores who has three screening interviews already booked that afternoon. Sales teams hit it when a rep returns from leave to a pile of untouched leads that aged past their response window while the rotation kept feeding them.

When to stop building and route instead

The Flow build above is genuinely good, and for a stable team of five reps handling interchangeable inbound it is the right answer. Build it and move on. The point where it stops paying for itself is well defined: when rotation has to respect who is available, when workload matters more than count, when different records need different skills, or when several rotations have to coexist and somebody has to keep all of them correct.

That is what Assigner does beside the Salesforce you already run. It keeps real rotation state, so round-robin assignment survives people joining and leaving, weighted rotation lets a half-time rep carry half the load by design, workload balancing distributes open effort instead of record counts, and availability routing takes people out of the rotation when they are off without anybody editing a checkbox. Every assignment records the rule that made it and the candidates it considered, priced at $12 per user per month. If you want the wider picture on the lead side first, Salesforce round robin assignment compares the native options, and our comparison against native assignment rules is honest about where staying native wins.

Frequently asked questions

How do I create a round robin in Salesforce Flow?

Create a custom object holding one row per eligible user with a date-time field recording when each was last assigned. In a record-triggered Flow, use Get Records on that object filtered to active rows and sorted by the date-time ascending, storing only the first record. Set the triggering record's OwnerId to that user, then update the same row's date-time to now so the next record goes to somebody else.

Does Salesforce have native round robin assignment?

No. Neither lead assignment rules, case assignment rules, nor Flow include a rotation option on any object. Assignment rules match criteria and stop, and they hold no memory of who received the previous record. Any round robin in Salesforce is something you build and maintain yourself, either in Flow with custom objects, in Apex, or with a routing tool that keeps the rotation state for you.

Can Salesforce Flow update a custom metadata type?

No. Flow can read custom metadata records with Get Records, but there is no supported way to create or update them from a Flow, which is why third-party invocable actions exist to do it. That rules custom metadata out as a place to store a rotation counter. Use a list custom setting instead, or better, a custom object row per assignee, because Flow can write to both.

How do I round robin leads that land in a queue?

Set the entry condition of your record-triggered Flow to OwnerId starts with 00G, the ID prefix for Group records, which is how every queue is stored. That reads as "this record is on a queue and nobody has claimed it". User IDs start with 005, so the Flow will not fire on records that already have a human owner, and assignment rules can keep deciding which queue a record reaches.

Why is my Salesforce round robin uneven?

The three usual causes are a missing stamp, a bulk load, and absent reps. If the Flow sets the owner but never updates the last-assigned field, everything goes to the same person. If records arrive in one large batch, several can read the same next assignee before any update commits. And an inactive or absent rep whose row is still active keeps drawing their full share of records that nobody works.

Should I use a counter or a timestamp for round robin in Flow?

Use a timestamp on an assignee record. A counter with modulo arithmetic depends on the number of reps staying constant, so adding or removing one reshuffles the rotation for everybody and leaves the index pointing somewhere unintended. A last-assigned date-time has nothing to invalidate: adding a rep is one new row, removing one is unticking a checkbox, and the sort keeps working.

Can Flow trigger Salesforce lead assignment rules?

Not with a standard element. Record-triggered Flow has no built-in option to run lead or case assignment rules, so orgs that need both usually call an invocable Apex action that sets Database.DMLOptions with the assignment rule header. The common alternative is to let the assignment rule run natively on creation and have the Flow act afterwards, once the record is already sitting on the queue the rule chose.

Stop hand-sorting your incoming work

Route every ticket, lead, and request to the right available person by skill, workload, and availability, using rules you control, and every assignment shows why. Rules you control, no black box.