How to build a NetSuite budget vs actual report
Build a NetSuite budget vs actual report that reconciles: budget loading, period alignment, variance columns and department dimensions.
A NetSuite budget vs actual report compares posted GL amounts to a loaded budget for the same account, period and subsidiary. Build it in the Financial Report Builder by adding a budget column to an income statement, then a variance column of actual minus budget. Budgets must be imported per account, period and dimension first.
Key takeaways
- Budget vs actual is a join on four keys: account, period, subsidiary and dimension. If any one of them disagrees between the budget and the GL, the variance is fiction.
- NetSuite budgets are their own record type, loaded per account per period. A blank budget column almost always means the budget was saved against a different dimension combination, not that the report is broken.
- Actuals follow the posting period, not the transaction date. A 31 January invoice posted to February belongs in February's variance.
- Variance sign has to be interpreted per account type: actual minus budget is good for revenue and bad for expense, so label the column favourable/unfavourable rather than positive/negative.
- The Financial Report Builder handles the GL cleanly. The moment you need budget against a non-GL measure — headcount, units, orders — you are out of the report builder and into a query.
A NetSuite budget vs actual report looks like a two-column comparison and behaves like a four-way join. Most of the time it goes wrong the report itself is fine: the budget was loaded against a department the transactions never use, or against a subsidiary that rolls up differently, or into a period that closed under a different fiscal calendar. This walks through the data first, then the build, then the variance columns that actually survive a review meeting.
- Budget vs actual variance
- The difference between the amount posted to a general ledger account in a period and the budgeted amount for that same account, period, subsidiary and dimension combination. Expressed in currency and as a percentage of budget.
The budget record: what you are actually loading
In NetSuite a budget is not a field on an account. It is a separate record, and each row of it is keyed by a combination of dimensions. Set them up under Transactions > Financial > Set Up Budgets, or import them by CSV, which is what anyone with more than about fifty accounts does.
- Account — one budget line per GL account. Roll-up accounts do not budget automatically; if you budget the parent and post to the children, the parent shows a budget and the children show none.
- Accounting period — twelve monthly amounts per fiscal year, per account. A budget loaded as one annual figure will show the whole year against January and nothing after it.
- Subsidiary — required on OneWorld. Budgets are entered in the subsidiary's currency, which matters the moment you view the report consolidated.
- Department, class, location — optional, and this is the field pair that breaks most reports. Budget loaded with no department will not match actuals that carry one, and vice versa.
- Customer and item — available for revenue budgeting where you need it, and worth avoiding unless you genuinely plan at that grain.
- Budget category — only visible if the Multiple Budgets feature is enabled. Without it you have exactly one budget per year and no way to hold an original plan next to a reforecast.
Four ways to build the report, and what each costs you
There is no single right answer here. The choice depends on whether you need a formal financial statement, an operational drilldown, or a number in a spreadsheet by 9am.
| Approach | Good for | Where it stops |
|---|---|---|
| Standard Budget Income Statement | A fast, correct P&L with budget and variance columns. Respects your financial statement layout and account hierarchy. | Fixed column set. Limited flexibility on comparative periods and custom variance maths. |
| Financial Report Builder (custom) | Adding your own budget, variance, variance % and prior-year columns; alternate row layouts; department or class column headers. | GL accounts only. No non-financial measures, and column arithmetic is limited to what the builder exposes. |
| Saved search | Operational cuts of actuals with custom formula columns and drill-through to transactions. | Budget is a separate record with no join path from a transaction search, so a saved search cannot put both sides in one result set. See NetSuite saved search limitations. |
| SuiteQL or a SuiteAnalytics workbook | Any grain, any variance formula, budget against non-GL measures, output straight into a spreadsheet or a dashboard. | You own the definitions. Nothing stops you from double-counting intercompany lines or forgetting the posting flag. |
Put a number on what the monthly variance pack currently costs in hours before you decide how much to automate.
Building it in the Financial Report Builder
- 1.Start from the standard Income Statement rather than a blank report. Reports > Financial > Income Statement, then Customize. You inherit the account layout and the sign conventions, which is most of the work.
- 2.On the Edit Columns tab, add a column and set its type to the budget alternate range. Choose the same period range as your actual column, and pick the budget category if you run multiple budgets.
- 3.Add a variance column as a formula of the actual column minus the budget column, and a second column for variance as a percentage of budget. Name them explicitly — Var $ and Var % beat NetSuite's default column labels.
- 4.On Filters, set subsidiary, department, class and location to match the grain the budget was loaded at. Leave a dimension unfiltered and you sum across it, which is usually what you want at the top level and never what you want in a drilldown.
- 5.Set the period range using relative periods (last fiscal quarter, this fiscal year to date) rather than named periods. Absolute periods mean somebody re-edits the report every month and eventually forgets.
- 6.Save with an audience, not for yourself. A variance report that only one person can open becomes that person's second job.
Period alignment: the variance nobody can explain
Actuals in NetSuite belong to a posting period, and the posting period is not always the month on the transaction date. An invoice dated 31 January entered on 3 February, after January was closed, posts to February. Your variance report is right and your sales team's spreadsheet is right, and they disagree by that invoice.
- Always reconcile on posting period. If a stakeholder brings a number built on transaction date, that difference is the first thing to isolate.
- Adjustment periods sit outside the twelve monthly periods. They carry real postings and no budget, so any period-13 activity shows as pure unfavourable variance unless you exclude it or budget for it deliberately.
- Multiple fiscal calendars on OneWorld mean subsidiaries can have different period boundaries. A consolidated variance across two calendars is comparing different spans of days. Work out what your own period boundaries are with the fiscal period calculator before you argue about the number.
- Reopened periods change history. If someone reopens and reposts March, a variance pack exported in April no longer matches the same report run in May. Date-stamp your exports.
Variance columns that survive a review
Four columns of arithmetic answer almost every question a budget holder asks. More than that and people stop reading the report.
| Column | Formula | Why it earns its place |
|---|---|---|
| Actual | Sum of posted GL amounts for the period | The fact. |
| Budget | Budget amount for the same account, period and dimension | The plan, at the grain you actually planned at. |
| Var $ | Actual − Budget | Materiality is measured in currency. A 300% overspend on a $400 line is not news. |
| Var % | (Actual − Budget) ÷ Budget | Direction and severity. Undefined where budget is zero, so print a dash rather than a divide-by-zero. |
| YTD Var $ | Cumulative actual − cumulative budget, year to date | Separates timing from overspend. A line that is $40,000 over in March and $2,000 over YTD is a phasing issue. |
Sign convention is where variance reports lose credibility. Actual minus budget is favourable on a revenue account and unfavourable on an expense account, so a report that colours everything positive as green is wrong half the time. Either flip the sign by account type or label the column Fav / (Unfav) and let the reader do it. If you want the reasoning behind picking materiality thresholds and writing the commentary, that is covered in budget vs actual variance analysis.
Pulling actuals with SuiteQL when the report will not bend
Once you need budget against something that is not a GL account — revenue per head, spend per order, cost per unit shipped — the report builder is finished and a query starts. The actuals half is straightforward: post amounts live on transaction accounting lines, and the period comes from the transaction header.
SELECT
a.acctnumber AS account_number,
BUILTIN.DF(tal.account) AS account_name,
ap.periodname AS period,
SUM(tal.amount) AS actual_amount
FROM transactionaccountingline tal
JOIN transaction t ON t.id = tal.transaction
JOIN accountingperiod ap ON ap.id = t.postingperiod
JOIN account a ON a.id = tal.account
WHERE t.posting = 'T'
AND ap.isadjust = 'F'
AND ap.startdate >= TO_DATE('2026-01-01', 'YYYY-MM-DD')
AND ap.enddate <= TO_DATE('2026-06-30', 'YYYY-MM-DD')
AND a.accttype IN ('Expense', 'OthExpense', 'COGS')
GROUP BY a.acctnumber, BUILTIN.DF(tal.account), ap.periodname
ORDER BY a.acctnumber, ap.periodnameThree details in that query do the real work. t.posting = 'T' restricts to transactions that hit the GL, which drops sales orders and other non-posting documents. ap.isadjust = 'F' keeps period 13 out of a monthly comparison. And SUM(tal.amount) on accounting lines rather than transaction lines means debits and credits net correctly without you reasoning about the mainline flag. Run it through the SuiteQL formatter if you inherited it as one long line.
Multi-subsidiary, multi-currency variance
Budgets are entered in subsidiary currency. Consolidated reporting translates actuals at the rates in your currency exchange rate table, and translates budget at whatever rate type the report is configured for. If those two differ, you get variance that is pure FX and nothing to do with the budget holder. Report subsidiary-level variance in local currency for accountability, and consolidated variance for the board, and never mix them in one column. The mechanics of consolidation and elimination are their own topic, covered in NetSuite consolidated multi-subsidiary reporting.
Asking for the variance instead of building it
The arithmetic in a budget vs actual report is subtraction. The work is everything around it: matching the grain, agreeing the period basis, excluding adjustment periods, deciding sign convention, and rebuilding it slightly differently for each of six budget holders. That is a week a quarter for most finance teams, and it is why the report is usually a fortnight old by the time anyone reads it.
is built for that gap. Ask which cost centres are more than 10% over budget year to date, and by how much and get the answer computed live against your own NetSuite account, with the SuiteQL it ran printed underneath — so you can check the posting flag and the period filter yourself rather than trusting a black box. It is read-only by default and NetSuite-first, with Infor SyteLine, M3 and LN ready.
Frequently asked questions
Why is my NetSuite budget column blank?
Almost always a grain mismatch. Budgets are stored per account, period, subsidiary and optional department, class or location. If the budget was loaded without a department but your report groups by department, NetSuite has no budget row to show. Check the budget record's dimensions against the report's grouping and filters, and confirm the subsidiary and fiscal year match.
How do I import budgets into NetSuite by CSV?
Use Setup > Import/Export > Import CSV Records and choose the Budgets import type. One row per account per period per dimension combination, with subsidiary included on OneWorld. Import into an open fiscal year, match the accounting period names exactly as NetSuite has them, and run a small test file first — budget imports overwrite rather than accumulate.
Can a saved search show budget and actual side by side?
No. Budget is a separate record type with no join path from a transaction saved search, so you cannot get both measures into one saved search result. Use the Financial Report Builder for GL comparisons, or a SuiteQL query or SuiteAnalytics workbook if you need a custom grain or a non-GL measure alongside the budget.
Should budget vs actual use transaction date or posting period?
Posting period. Budgets are loaded per accounting period, and the GL is closed per accounting period, so posting period is the only basis on which the two sides tie. Transaction date differs whenever something is entered after its month closed, which is common at the start of every month and is the most frequent cause of unexplained variance.
How do I hold an original budget and a reforecast in NetSuite?
Enable the Multiple Budgets feature, which adds a budget category to the budget record. Load the original plan under one category and each reforecast under another, then choose the category on the report column. Without that feature you have one budget per fiscal year and reforecasting means overwriting the plan you are trying to measure against.
Why does consolidated budget variance differ from the sum of subsidiary variances?
Currency translation. Budgets are entered in subsidiary currency, and consolidation translates actuals and budget using the rates configured for the report. If the two sides translate at different rates, the difference appears as variance that no budget holder caused. Review local-currency variance for accountability and consolidated variance for group reporting.
Calculators for this
Reporting time savings calculator — price the hours your team spends building reports, the annual cost, hours recovered and the FTE equivalent.
Find the fiscal year, quarter and period for any date from your fiscal year start month. Supports 4-4-5 retail calendars and lists every period boundary.
Format SuiteQL and SQL in your browser: keyword casing, clause line breaks, indented joins and subqueries, plus a one-line minify mode.
Keep reading
Build a budget vs actual variance analysis that holds up: materiality thresholds, price/volume/mix drivers, and timing versus permanent.
The real ceilings of NetSuite saved searches: join depth, summary maths, row limits and performance, plus the right tool to use for each one.
How NetSuite consolidated multi-subsidiary reporting works: consolidated exchange rates, elimination subsidiaries, CTA, and the subsidiary-context traps.
Build a top customers by revenue report in NetSuite, and see why revenue, invoiced and collected give three different rankings of the same customers.