An Accounting Migration With No Downtime
A finance platform had reached the point where routine change threatened posting integrity and connected operational systems. The migration moved accounting authority in controlled stages while preserving open items, document lineage and normal business processing.
- Engagement
- Accounting platform migration
- Duration
- A little over a quarter
- Team
- Application and data engineers with a finance business analyst

This account is anonymised. The client is described by sector rather than by name, and outcomes are described in words rather than figures — no percentage or saving is quoted because none can be independently evidenced here.
A ledger at the centre of too many implicit contracts
The incumbent application was more than a ledger. Operational systems sent invoices and cash events through undocumented interfaces, finance maintained mapping workbooks around its nominal codes and period-end routines depended on reports whose selection logic was no longer visible. A direct replacement of screens and tables would not preserve these contracts. It would preserve their names while changing their meaning. The organisation also could not suspend billing, receipts or supplier processing for a migration weekend. Transactions would continue to arrive while opening balances were being proved, creating a moving boundary between systems that had to be designed rather than wished away.
The work began by identifying accounting events and control populations: issued invoices, credit notes, receipts, allocations, supplier liabilities, journals and period states. For each, the team recorded the authoritative source, posting rule, currency treatment, correction path and evidence needed to explain the resulting balance. Historical reporting and live operational processing were separated. The target needed enough converted detail to settle open items and answer current enquiries, while immutable legacy snapshots could serve older drill-down where wholesale transformation would add risk without operational value. This allowed the cut-over to be framed as a controlled transfer of accounting responsibility, with explicit reconciliation at every boundary.
What shaped the build
No processing shutdown
Billing and cash processing had to continue while the new ledger was loaded, reconciled and made authoritative.
Fixed reporting window
The transition sat between established close and review activities that could not be moved to accommodate software delivery.
Undocumented interfaces
Connected systems relied on file layouts, account mappings and retry behaviour that had evolved outside formal specifications.
Historical evidence
The organisation needed to retain source documents, approvals and the relationship between legacy entries and reported balances.
How the engagement ran
- 01
Inventory accounting events
We traced each posting population from operational source through transformation, ledger entry, reconciliation and report consumption.
- 02
Establish the target controls
The chart, dimensions, periods, currencies, permissions and immutable correction model were configured before transaction conversion.
- 03
Build a repeatable migration
Extract, transformation and load stages produced stable lineage and control reports rather than one-off amended files.
- 04
Run both boundaries
Interfaces were shadowed and outputs compared while the incumbent remained authoritative, exposing timing and semantic differences.
- 05
Transfer and prove
Authority moved according to a transaction watermark, followed by open-item, control-account and report reconciliation.
Define accounting meaning before mapping codes
Legacy account codes were not treated as self-explanatory. The same code could receive subledger postings, direct journals and imported adjustments, each with different dimensions and evidence. Workshops therefore started with representative events and their intended financial meaning. The target chart kept natural accounts restrained and moved changing management analysis into governed dimensions. Posting rules specified required and prohibited combinations, permitted sources and period behaviour. Control accounts accepted only authorised subledger events except through an explicit correction route. This design prevented a superficially complete code-to-code mapping from carrying forward ambiguous usage and made every unmapped population a decision for finance rather than a convenient suspense posting.
The posting engine enforced balanced journals within the relevant entity and currency context. Entries became immutable after posting; reversal and adjustment linked back to the original event. Exchange rates retained source, effective date and type, while rounding was handled consistently at the journal boundary. Closed periods rejected ordinary events and exposed a separate authorised adjustment process. These controls were tested through complete scenarios including invoice correction, partial settlement, refund, write-off and late receipt. The objective was not simply to reproduce a trial balance. It was to show that future transactions would reach the correct accounts, carry the required dimensions and remain explainable after correction.
Move open items as operational records
A receivables balance alone cannot support allocation, dispute handling or customer enquiry. Open invoices were therefore converted with their document identifiers, dates, currency, outstanding components, tax treatment and links to available source evidence. Receipts on account, partial allocations and credits retained their relationships. The same approach applied to supplier items and unposted operational events near the boundary. Transformation rules distinguished a malformed source value from an absent optional value, and rejected records stayed visible with an assigned resolution. Nothing was made loadable by replacing uncertainty with a plausible default. Once corrected, the entire pipeline could be rerun from the same source snapshot.
Historical transactions followed a different policy. The target received the detail required for comparative reporting and current operations, but the migration did not manufacture target-system workflows for events completed under the legacy application. A read-only archive preserved original journals, documents and approvals with controlled access. Cross-reference keys connected converted openings to their source population and stored the transformation version. Reports identified records represented as opening detail separately from transactions genuinely posted in the target. That distinction protected audit interpretation: a converted entry could be traced and reconciled without implying that the new approval workflow had existed when the original transaction was authorised.
Use a transaction watermark, not a vague cut-off
Continuous processing required a precise boundary for each inbound source. Depending on the integration, that boundary was a durable event identifier, source sequence or accepted timestamp paired with an identifier. Initial loads established state up to the agreed watermark. Events after it entered a delta path with the same validation and idempotency controls used by live interfaces. Producers retained their own identifiers, allowing retries to return the original result rather than post again. Where a source could amend an earlier event, the contract represented that change explicitly instead of relying on file replacement. This made the overlap between migration and live operation deterministic.
Interfaces were run in shadow before authority transferred. The new platform consumed representative traffic and generated proposed postings without releasing them to the ledger. Comparison operated at event and journal-line level, not only on aggregate debits and credits, because equal totals can conceal account, dimension or date errors. Timing differences were classified separately from mapping defects. Operational acknowledgements were also tested: a source needed to know whether an event was accepted, rejected or already processed, and support staff needed the same answer without querying database tables. At transfer, routes changed according to the recorded watermark, with queues drained and reconciled rather than discarded.
Build reconciliation into the migration product
Every rehearsal produced a migration control pack from the pipeline itself. It compared extracted, transformed, rejected and loaded populations; bridged the legacy trial balance to target openings; reconciled subledger open items to their control accounts; and listed mappings or documents that needed review. Reports used stable record identifiers and linked to transformation diagnostics. Finance sign-off therefore referred to a reproducible run rather than emailed workbooks amended after extraction. When a rule changed, the next run exposed its effect across all affected records. This shortened investigation and avoided the familiar problem in which the final migration succeeds only because nobody can reproduce the manual repairs made to it.
The first target close used the same controls intended for ordinary operation. Subledger reports reconciled to ledger control accounts under a shared cut-off definition, posting batches connected back to accepted source events and manual journals carried preparation and approval history. Comparative reports were traced through target dimensions and legacy archive links. Access to migration staging data was reduced after acceptance, while the evidence bundle and immutable source snapshots followed the agreed retention policy. Decommissioning was conditional on evidence and retrieval, not merely on successful login to the new application. The organisation could continue processing throughout because the transition had been engineered as a sequence of owned states, not compressed into an unexplained outage window.
What changed
- Billing and cash processing continued while accounting authority moved between platforms.
- Open receivables and payables remained operational records rather than unexplained opening balances.
- Month-end reconciliation stopped depending on privately amended mapping workbooks.
- Retried integration events no longer carried a risk of duplicate posting.
- Historical evidence remained distinguishable from transactions created under the new controls.
Stack
- .NET
- C#
- PostgreSQL
- React
- TypeScript
- Azure Service Bus
Common questions
Can an accounting platform be migrated without downtime?
Yes, when each source has a durable transaction boundary and delta events can be replayed safely. Reconciliation must cover the overlap as well as the opening load.
How much accounting history should move to the new system?
Only history required for live operation and agreed reporting should be transformed into target records. Older evidence can remain in a controlled read-only archive with cross-references from converted balances.
How are open invoices migrated safely?
They move with settlement state, currency, document identity and source lineage, then reconcile to the relevant control account. Partial allocations and credits must remain relationships, not flattened balances.
What proves that the migrated ledger is correct?
A repeatable control pack bridges source extraction through transformation to loaded records and financial statements. Event-level sampling and complete accounting scenarios complement, rather than replace, balance reconciliation.
Describe your version of this.
The constraints are never identical, and that is usually where the interesting engineering is. Tell us what yours are.


