Almost every finance organization running Anaplan eventually hits the same wall: the P&L is accurate at the legal-entity level and useless at the level people actually manage. IT costs sit in a single cost center. Shared services — HR, finance, facilities, the data platform team — are a black box. Product margin is a spreadsheet somebody maintains offline, and nobody in the business believes it.
Allocations are the fix, and they are also the single most commonly botched module set in an Anaplan estate. Teams either hard-code a driver table that nobody can maintain, or they build a chain of allocation steps so opaque that the output cannot be reconciled back to the general ledger. This tutorial walks the build for a multi-step cost allocation engine: driver capture, sequential (step-down) allocation, reciprocal shared-services charges, chargeback reporting that a cost center owner will accept, and the reconciliation controls that keep the whole thing trustworthy.
It assumes you are comfortable with lists, subsets, SUM/LOOKUP, and the difference between a structural and a transactional module. It pairs naturally with an opex and cost center budgeting model upstream — allocations consume the budget, they do not replace it.
Decide the allocation policy before you build anything
The most expensive mistake in an allocations project is starting in Anaplan. Allocation logic is an accounting policy, and if the policy is unsettled the model becomes a negotiating table. Get four answers in writing first.
- What is allocated? Usually a defined set of cost pools — not the whole P&L. Direct costs stay where they land.
- On what basis? Each pool needs one driver: headcount, square footage, ticket volume, revenue, transaction counts, compute consumption.
- In what order? Support functions consume each other. Facilities charges IT for floor space; IT charges Facilities for laptops. The order determines the answer.
- Who can dispute it, and how? If there is no dispute mechanism, cost center owners will simply refuse to own the numbers.
Write these down as a one-page allocation policy and get it signed. The model implements the policy; it does not invent it.
Step 1: The dimensional skeleton
Keep the allocation engine in its own module set — ideally its own model if you are also running detailed budgeting — and feed it from the actuals data hub and the plan model.
| List | Type | Notes |
|---|---|---|
Cost Centers | Hierarchy: Function > Department > Cost Center | The receiving and sending dimension |
Cost Center Type | Flat (Direct, Shared Service, Corporate) | Drives which centers are senders |
Accounts | Hierarchy, mirrors GL rollups | Allocated costs need an account identity downstream |
Cost Pools | Flat, ~15–40 members | The unit of allocation policy, not the GL account |
Allocation Steps | Flat, numbered 010, 020, 030… | Explicit ordering; never rely on list creation order |
Drivers | Flat (Headcount, Sq Ft, Tickets, Revenue, Compute Units…) | One driver per pool per step |
Receiver Objects | Optional: Products, Channels, Regions | Only if you allocate beyond cost center |
Time | Monthly, with a rolling range | Allocations rarely need weeks |
Two design rules that save rework later:
- Cost pool is not the same as GL account. A pool like Corporate IT Infrastructure may draw from twelve accounts across three cost centers. Map accounts and cost centers to pools in a mapping module; do not force the GL to carry allocation semantics.
- Steps are first-class list members. Modeling steps as a list rather than as separate modules means adding a step is a data change, not a build change. That is the difference between a model finance can maintain and one that requires a consultant every quarter.
Step 2: Capture the source pool
Build ALL01 Cost Pool Source dimensioned by Cost Pools × Time × Version:
Direct Cost Loaded— imported from actuals or plan, summed via the account/cost-center mapping.Prior Step Received— costs pushed into this pool by earlier allocation steps.Pool To Allocate=Direct Cost Loaded + Prior Step Received.Excluded Amount— manual carve-outs (a one-off legal settlement nobody wants smeared across the business).Net Pool=Pool To Allocate - Excluded Amount.
The Prior Step Received line is what makes the engine sequential rather than single-pass. It is populated by the step loop below, and it is the reason step ordering matters.
Step 3: Driver capture and normalization
Drivers are where allocation models rot. Somebody loads headcount once, it goes stale, and by month six the allocation is defensible only in the sense that nobody can be bothered to check it.
Build ALL02 Driver Values dimensioned by Cost Centers × Drivers × Time:
Raw Driver Value— imported from the source of truth for each driver (workforce model for headcount, facilities system for square footage, ITSM export for tickets).Manual OverrideandOverride Flag— with a comment line item; overrides without comments are audit findings waiting to happen.Effective Driver=IF Override Flag THEN Manual Override ELSE Raw Driver Value.Eligible?— boolean from the receiver eligibility matrix (Step 4).Driver For Allocation=IF Eligible? THEN Effective Driver ELSE 0.
Then normalize in the same module:
Driver Total = Driver For Allocation[SUM: Cost Centers.All]
Driver Share = IF Driver Total = 0 THEN 0 ELSE Driver For Allocation / Driver Total
Guard the divide. A zero driver total in a single period — a new pool with no headcount loaded yet — will otherwise throw the entire step and, worse, silently strand the cost.
Add a Driver Staleness check: the number of periods since the raw value last changed. Surface it on the admin dashboard. A driver that has not moved in nine months is either stable or abandoned, and you want to know which.
Step 4: Sender/receiver eligibility
Not every cost center should receive every pool. Build ALL03 Allocation Rules dimensioned by Allocation Steps × Cost Pools × Cost Centers:
Is Sender?— which pool this step drains.Is Eligible Receiver?— boolean, maintained by finance.Receiver Weight— optional multiplier for policy adjustments (a site that gets half the facilities charge because it is subleased).Driver Applied— a list-formatted line item pointing atDrivers.
Eligibility maintenance is a chore, so make it a chore you can do in a grid: one page, filtered to a step, booleans across cost centers, published to the UX with a save action. If maintaining the rules requires an import template, they will not be maintained.
Rule of thumb: a sender never receives its own allocation in the same step. Enforce it in the formula rather than trusting the boolean grid:
Eligible Receiver Final = Is Eligible Receiver? AND NOT Is Sender?
Step 5: The step-down engine
Now the core. Build ALL04 Step Allocation dimensioned by Allocation Steps × Cost Pools × Cost Centers × Time:
Amount To Allocate = Net Pool (LOOKUP from ALL01, filtered to this step's pool)
Share = Driver Share (LOOKUP from ALL02 on Driver Applied)
Allocated Amount = Amount To Allocate * Share * Receiver Weight Normalized
Sequencing is the part people get wrong. Anaplan has no procedural loop, so you have two viable patterns:
Pattern A — bounded unrolled steps (recommended). Fix the number of steps (five to eight covers most estates), and give each step its own set of line items in a single module: Step 1 Received, Step 2 Received, and so on, where Step N Received feeds Step N+1's pool balance. It is verbose but every intermediate value is visible, which is exactly what you want in an auditable process.
Pattern B — action-driven iteration. Calculate one step, run an action that copies results into an input line item, recalculate, repeat. Wrap it in a process so users click once. It is more compact, but it introduces state: the model is only correct after the process has run. If you choose this, put a big, hard-to-miss "last allocation run" timestamp on every allocation dashboard.
For reciprocal costs — IT and Facilities charging each other — a two-pass approximation is almost always enough. Pass one allocates IT to everyone including Facilities; pass two allocates Facilities (now including its IT charge) to everyone except IT. Residual error is typically well under a percent, and finance teams accept it far more readily than a simultaneous-equations solution nobody can explain. If a true reciprocal solve is required by policy, that is an Anaplan Optimizer problem, not a formula problem.
Step 6: Fully-loaded reporting and chargeback
The engine produces allocated amounts. What the business consumes is a fully-loaded view. Build ALL05 Loaded P&L by Cost Centers × Accounts × Time:
Direct CostAllocated In— sum of allAllocated Amountwhere the cost center is receiver.Allocated Out— negative, where it is sender.Fully Loaded Cost=Direct Cost + Allocated In - Allocated Out.
Carry the allocated amounts to a dedicated allocation account (or account group) rather than smearing them across the original natural accounts. Cost center owners need to see "IT chargeback: $412,000" as a line, not a mysterious inflation of their travel budget.
For chargeback transparency, build a drill module by Cost Centers × Cost Pools × Time showing, for each receiving center: the pool, the driver used, the center's driver value, the total driver, its share, and the resulting charge. That single grid resolves the overwhelming majority of allocation disputes before they reach a meeting.
Then add a dispute workflow: a boolean Disputed?, a text Dispute Reason, and a numeric Proposed Adjustment on the receiving side, reviewed by the allocation owner. Anaplan Workflow can carry the approval if you want it formalized.
Step 7: Reconciliation controls
An allocation engine without controls is a rumor. Build ALL06 Allocation Controls with these checks, all of which should read zero:
| Check | Formula intent |
|---|---|
| Pool fully allocated | Net Pool - Total Allocated for every pool and step |
| Zero-sum | Allocated In - Allocated Out across all cost centers |
| GL tie-out | Total Fully Loaded Cost - Total Direct Cost (allocation must not create or destroy cost) |
| No self-allocation | Sum of allocations where sender = receiver |
| Stranded cost | Pool amount where driver total = 0 |
| Negative allocation | Count of negative allocated amounts where the pool is positive |
Publish them as a single control panel with conditional formatting, and make green lights a precondition for closing the allocation cycle. In practice the stranded-cost check catches more real problems than all the others combined — it is the one that fires when a new cost center opens and nobody added it to the eligibility grid.
Performance and maintenance notes
- The
Allocation Steps×Cost Pools×Cost Centers×Timemodule is the big one. Keep the pool list short and resist adding receiver dimensions (product, channel) unless the policy genuinely requires them; each one multiplies cell count. - If you must allocate to product or channel, do it in a final single step from the fully-loaded cost center view, not inside the step-down engine.
- Calculate
Driver Shareonce inALL02. Recomputing normalization inside the allocation module multiplies the same divide across every step. - Keep drivers on a monthly time range even when the plan model runs weekly.
- Version the allocation rules by scenario if the business wants to test "what if we allocate IT on compute consumption instead of headcount" — this is one of the highest-value things an allocation model can do, and it is impossible in a spreadsheet.
- Put the rules, drivers, and controls behind ALM revision control like any other structural change. Driver values are data; driver rules are structure.
The failure mode to watch for
Allocation models fail socially, not technically. The formulas are simple; the arithmetic ties out; and yet six months later three business units maintain shadow spreadsheets because they do not trust the charge. The antidote is transparency built into the model from day one: visible drivers, visible shares, a drillable chargeback grid, a working dispute path, and controls anybody can read. Build those before you tune the last basis point of the reciprocal solve.
QuanticPlanning designs and builds Anaplan cost allocation, profitability, and cost center models — including rescuing allocation engines that no longer reconcile. If you are scoping an allocations build or trying to make an existing one defensible, get in touch.