The Shift Rota Builder, Explained

After reading this you will know how a weekly rota gets built one slot at a time, why "give it to the least-loaded person" produces a nearly even workload, and how to read the result and spot when the week is impossible.

What the tool does and one quick example

You give the tool a list of people, the days you want covered, how many shifts each day has, and how many people each shift needs. It returns a full week of assignments where the total work is spread as evenly as it can be, and where nobody is scheduled twice on the same day.

Here is the shape of the problem in miniature. Say you have four people and a Monday with two shifts, one person per shift. That is two slots to fill from four candidates. The obvious move is to hand the two slots to the two people who have worked the least so far. Do that every day, across every slot, and the counts stay close together. The rest of this article makes "close together" precise.

The tool solves a matching problem: it assigns slots (jobs) to people (workers) subject to constraints. It is greedy first, then it repairs itself with swaps.

When to use it, and when not

Use it when every shift is interchangeable and your only goals are coverage and fairness. A café counter, a help desk, a volunteer table, a ward of nurses who can all do the same tasks: these fit well. The tool treats one shift like any other, so the fairness metric is simply the number of shifts per person.

Do not use it when shifts differ in a way that matters. If Saturday night is worth two weekday mornings, the tool does not know that. If some people can only do specific roles (a till versus a kitchen), the tool has no concept of role. It knows only who is unavailable on which days. Model those richer constraints elsewhere, or split the problem into separate rotas per role.

The tool balances count of shifts, not difficulty or desirability. Two people with three shifts each are "equal" to the tool even if one worked three quiet mornings and the other worked three busy nights.

The rule that drives everything

The core rule is one line. For each slot, in order, pick the person with the smallest current load among those available that day and not yet used that day.

\text{next} = \arg\min_{p \in A} \; L(p)

Here A is the set of eligible people for this slot: available on the day and not already assigned to another shift the same day. L(p) is how many shifts person p already holds this week. \arg\min just means "the person who minimizes that count". Ties are broken by list order, which keeps the output stable and reproducible.

Why does this stay fair? The total number of shifts is fixed. With D days, S shifts per day and N people each needed per shift, the total assignments are:

T = D \cdot S \cdot N

If everyone were available every day, perfect fairness would give each of P people either \lfloor T/P \rfloor or \lceil T/P \rceil shifts. Always feeding the next slot to the least-loaded person is exactly the way to keep every count inside that one-unit band. Unavailability can push a specific person off a day, which is why a swap pass runs afterward to mop up any imbalance the greedy pass could not avoid.

A worked example with the demo data

Five people, Monday to Friday, two shifts a day

Load the demo. The staff are Anna, Ben (out Mon, Tue), Cara (out Sun), Dana (out Wed), and Erik. Days are mon-fri, with 2 shifts a day and 1 person per shift.

  1. Total slots: T = 5 \times 2 \times 1 = 10. Five people share ten shifts, so perfect fairness is two shifts each.
  2. Cara's "out Sun" never bites, because Sunday is not scheduled. Ben is out Mon and Tue. Dana is out Wed. Everyone else is fully free.
  3. Monday, two slots. Ben is unavailable, so the eligible pool is Anna, Cara, Dana, Erik, all at load 0. Take the first two in list order: Anna, then Cara. Loads are now Anna 1, Cara 1.
  4. Tuesday, two slots. Ben out again. Eligible at lowest load are Dana and Erik (both 0). Assign Dana, then Erik. Loads: Anna 1, Cara 1, Dana 1, Erik 1, Ben 0.
  5. Wednesday, two slots. Dana out. The least-loaded available person is Ben (0). Assign Ben, now at 1. The next lowest available is Anna, Cara, or Erik, all at 1; take Anna. Loads: Anna 2, Ben 1, Cara 1, Erik 1, Dana 1.
  6. Thursday, two slots. All free. Lowest loads are Ben, Cara, Dana, Erik at 1. Assign Ben (now 2) and Cara (now 2).
  7. Friday, two slots. Lowest are Dana and Erik at 1. Assign both. Final loads: Anna 2, Ben 2, Cara 2, Dana 2, Erik 2.

Every person lands on exactly two shifts. That is perfectly even, and it happened even though Ben lost two candidate days and Dana lost one. The greedy rule handled it with no swaps needed.

All five people carry two shifts. The bars are equal, which is the ideal outcome when T divides evenly by P.

Try it: how unavailability bends fairness

Perfect balance is common but not guaranteed. Once one person is blocked on many days, the shifts they cannot take must go somewhere, and the counts start to spread. The widget below lets you watch that happen.

With five people over Monday to Friday and two shifts a day (ten shifts), perfect fairness is two each. If one person is unavailable on 0 days, everyone gets 2. Block that person on 3 days and they can still reach 2, since seven open days remain across the other four people. Block them on all 5 days and they get 0 while the load 10 splits over four people as 3, 3, 2, 2: a spread of one shift.

Reading and interpreting the result

Look at the per-person totals first. If they differ by at most one shift, the rota is as fair as arithmetic allows, and you are done. A spread of one is normal whenever T does not divide evenly by P. With four people and ten shifts, for instance, the only fair split is 3, 3, 2, 2.

A spread of two or more deserves a second look. It usually means someone's unavailable days forced work onto a small set of people. Read down the blocked days: if one person is out four of five days, they simply cannot carry an even share, and the tool spread the rest as flatly as it could.

To check fairness by hand, compute T / P and round down and up. Every person should land on one of those two numbers. In the demo, 10 / 5 = 2 exactly, so everyone must be at 2. Anything else would be a bug.

Common mistakes

The most frequent error is asking for more coverage than the people can supply. If Wednesday needs three people on shift but only two are available that day, no valid rota exists. The tool checks this before it builds anything and tells you which day fails, rather than quietly producing a broken schedule.

The second mistake is expecting balanced days. The tool balances shifts per person over the whole week, not per day. One person can legitimately work Monday and Tuesday while another works Thursday and Friday; both hold two shifts, so both are fair by the metric.

A third mistake is misreading the unavailable-day syntax. Write the day abbreviations after a colon, as in Ben: Mon, Tue. Days you do not list count as available. A name with no colon, like Anna, is available every scheduled day.

The rota is a heuristic: greedy first, then local swaps. For a single week it reliably lands within one shift of perfectly even, but it does not prove optimality across, say, difficulty-weighted shifts. If you need weighting or roles, the tool cannot express them.

Related tools

If your problem is really about pairing two sides by preference rather than spreading a workload, for example matching mentors to mentees or interns to departments, use the Stable Matching Calculator, which runs Gale-Shapley from two ranked lists. If you need the best order to visit a set of stops rather than who covers which shift, use the Errand Route Optimizer, which is exact for up to twelve stops.

Frequently asked questions

Why did two people end up with different shift counts?

Because the total shifts did not divide evenly by the number of people, or because someone's unavailable days blocked them from an even share. Compute T / P: if it is not a whole number, a spread of one is unavoidable and correct.

Can the same person work two shifts on one day?

No. The tool never assigns a person to two slots on the same day. If a day has two shifts, they go to two different people.

What happens if a day has fewer available people than it needs?

The tool reports that the week is infeasible and names the failing day, instead of returning a rota that cannot be staffed. Add availability or reduce the people-per-shift for that setup.

Is the schedule guaranteed to be the fairest possible?

For one week, in practice, yes to within one shift per person. The method is greedy plus local swaps, which is a heuristic rather than a proof, but for the size of a weekly rota it consistently reaches the best or near-best even split.

Does listing order among staff matter?

Only for breaking ties. When several people share the lowest load, the tool picks the one higher in your list. This keeps the output stable and reproducible, but it does not change anyone's final shift count.