Wednesday, 16 September 2026

NAV to Business Central: What Actually Moves, and What Needs to Change?


In Part 1 I argued that NAV, GP and SL customers should start planning now instead of waiting for a lifecycle date to force the decision.

The next question is always more practical:

"What actually happens when we move from Dynamics NAV to Business Central?"

Most people picture one of two extremes. Either it's a database upgrade, or it's a rebuild from scratch. Neither is right, and the space between them is where most project surprises live.

So let me start with the thing that clears up the most confusion.

It isn't one move. It's an upgrade, then a migration

There is no supported route that takes a NAV database straight into Business Central online. The cloud migration tool moves data from a Business Central on-premises database into an online tenant. NAV isn't a valid source for it.

That means every NAV customer is doing two projects that get discussed as one:

1.      An upgrade, from your NAV version to a Business Central on-premises version the cloud migration tool supports. Usually more than one hop.

2.      A cloud migration, from that on-premises database into Business Central online.

Microsoft's documented routes look like this:

Your current version

Route to Business Central online

NAV 2015 through 2018, and BC 13

BC 14, then BC 25, then cloud migration to online

NAV 2013 / 2013 R2

NAV 2018, then BC 14, then BC 25, then online

NAV 2009 SP1 / 2009 R2

NAV 2013 or 2015, then NAV 2018, then BC 14, then BC 25, then online

There are two mandatory waypoints on that route, and both catch people out.

Version 14 (the 2019 Spring release) is the last version that still understands the old development model, which is exactly why every path passes through it. Worth knowing: its mainstream support ended in October 2023, minor updates stopped, and new customers can't run it in production. It exists purely as a stepping stone.

Version 25 (2024 release wave 2) became mandatory more recently. Starting with 2025 release wave 1 (v26), direct upgrade from version 14 to the latest release stopped being supported, and the path now runs through v25. So you can't go from 14 straight to a current release. If your target is Business Central on-premises rather than online, add one more hop from v25 to the current version on top of that.

The practical consequence: your NAV version doesn't just affect effort, it determines how many technical upgrades you're doing before the migration even begins. A NAV 2018 customer is doing two, to 14 and then 25. A NAV 2009 customer is doing four. That's why "which version are we on" is the first question I ask, and why the answer moves the timeline more than the customization count does.

One caveat on the numbers above. Waypoints shift with release waves, and the v25 requirement itself only appeared with v26. Check the current supported upgrade paths on Microsoft Learn before you build a plan around any specific version.

What "moves" actually means

The cloud migration itself is data replication. You install an Integration Runtime next to your on-premises database, connect it to the online tenant, select companies, and run replication through Azure Data Factory. Initial load, then deltas, then a data upgrade on the online side, then you complete the migration so the online environment becomes the primary system.

Two things follow from that, and the second one catches people out.

Code does not replicate. Tables and fields exist in the cloud only because an extension in that tenant declares them. There is no mechanism that carries application objects across.

And your data is coupled to that code. Data from tables with code customizations can't be carried forward unless those customizations are handled by extensions installed both on-premises and online.

That second point deserves a second read. It isn't only "your C/AL has to be rewritten." Your data in customized tables has nowhere to land until the matching extension exists on both sides of the replication. A custom field on the Item table, or a custom table holding ten years of quality inspection records, stays behind until the AL extension defining it is installed in both environments.

If there's one sentence I'd want a NAV customer to absorb before anyone estimates anything, it's that one.

The real decision: full migration or reimplementation

Microsoft documents two paths, and choosing between them shapes the whole project.

Full migration. All data and customizations. Requires converting C/AL to AL extensions and upgrading through to a current version. This is what people usually mean when they say "migration."

Reimplementation. Essential business data only: master data, balances, a subset of posted historical entries, and setup. It doesn't require converting your extensions, and it doesn't require upgrading beyond version 14. There's a dedicated Business Central 14 reimplementation tool for it.

Both paths still require reaching version 14 first. That part isn't optional.

Both approaches are valid. The right choice depends on the customer's data, customizations, integrations and business requirements, and I've seen both work well.

Full migration tends to fit when:

  • Historical transactions are operationally necessary, for example serial and lot traceability, long-running service contracts, or warranty claims against old shipments.
  • Customizations are still central to how the business runs, so they need to exist in AL regardless.
  • Audit or statutory obligations depend on detailed history being available inside the ERP.
  • The third-party solutions in use have Business Central online equivalents.

Reimplementation tends to fit when:

  • History is needed for reference and can reasonably live in a reporting or archive system.
  • A meaningful share of customizations turn out to be workarounds, unused, or now standard functionality.
  • The business wants to standardize processes rather than carry existing ones forward.
  • Some customized tables have no clear business owner willing to fund converting them.

If the choice isn't obvious, estimate both. The comparison usually tells you more about the project than either estimate does on its own.

What I'd avoid is treating this as a technical footnote. It's a business decision about what the company actually needs in the new system, and it belongs in the first few conversations, not in a design document six months later.

What usually needs technical work

C/AL customizations

They don't run in Business Central. Not online, and not in modern on-premises versions either, since C/AL was removed from the product entirely. Everything has to become AL extensions, or has to be dropped.

That doesn't mean rewriting line for line. Some of what you customized in 2012 is standard functionality now. Some was a workaround for a limitation that no longer exists. Some nobody uses. I'll cover how I assess this in Part 3.

Reports

Many NAV environments carry years of customized reports. Before converting any of them, I answer two questions: is this report still being opened, and does Business Central already provide an equivalent? Report usage data from your existing system is more reliable here than asking users, who tend to say yes to everything.

Integrations

Integrations deserve their own workstream. NAV environments connect to banking, CRM, payroll, warehouse systems, shipping providers, tax portals and in-house applications. Anything that authenticated against an on-premises service, used a fixed internal endpoint, or relied on file drops on a shared folder needs rework for a cloud tenant.

I've seen a project where the data migration completed cleanly and the numbers reconciled, and users still couldn't work on day one, because an integration nobody had listed as in scope was the thing that actually fed daily transactions into the system.

Third-party solutions

This is the item most likely to set your timeline, and it's the one people discuss last. If an add-on isn't available as an app for Business Central online, you either replace it, rebuild the functionality, or reconsider the path. Check availability early, because the answer can change the whole plan.

Permissions and licensing

NAV permission sets don't carry across cleanly, and licensing works differently. Essentials and Premium are licensed per user, and license type assignment affects what people can do. Teams users with certain Microsoft 365 plans can get read-only access to Business Central data at no extra cost, provided the organization holds at least one Business Central license. This is worth modelling properly rather than discovering during user acceptance testing.

Job queues and scheduled processing

These don't arrive as working configuration. They get set up again, and the behavior differs from what your NAS-based processing did. Inventory them, because they're easy to forget and very visible when they're missing.

Localizations

Country and region specific functionality arrives in Business Central online through localization apps. Verify the localization you need is available for your country, and confirm that any locally customized tax, regulatory or statutory reporting logic has been converted into AL extensions that work with that localization. In my experience this is where India, and other markets with heavy statutory requirements, needs more attention than a generic project plan allows for.

Before you estimate anything

Part 1 listed the questions I'd ask during an assessment, so I won't repeat them here. But this stage adds three that are specific to the route:

1.      Which NAV version exactly, including build? This sets the number of upgrade hops, and each hop is a project with its own testing cycle.

2.      Does every customized table have an owner willing to fund its extension? If not, that data isn't moving, and the business needs to know now.

3.      Which third-party solutions have a Business Central online equivalent? Check before committing to a date.

Answer these and the migration stops being an open-ended question and becomes a scope you can price.

The bottom line

Moving from NAV to Business Central isn't a single event, and it isn't a choice between "everything moves" and "everything gets rebuilt."

It's an upgrade path to version 14 and beyond, followed by a data replication into the cloud, with one hard rule sitting underneath it: your data travels only as far as your code does.

Once a customer understands that, the interesting conversation starts. Not "can we migrate," but "what do we actually want to take with us."



Monday, 14 September 2026

How I Recreated the Extension Upload Experience in Business Central


Microsoft has deprecated the in-product upload on the Extension Management page and the Automation API extensionUpload endpoint. Both are scheduled for removal in 2027 release wave 1 (version 30). Extension Management is expected to survive only as a read-only list.

https://mohana-dynamicsnav.blogspot.com/2026/09/managing-apps-in-business-central-admin.html


The supported replacement is the Business Central admin center API so I built an app that calls it from AL.


PTE Extension Management gives you a page that looks and behaves like the one you already use:

  • Installed Extensions (Admin Center) live list of what is installed, with available update versions and scope.
  • Upload Extension — pick a .app, choose when to deploy (current version, update window, next minor, next major), set the schema sync mode, and accept the publisher terms.
  • Uninstall — with an optional, confirmed delete of the extension's data.
  • Installation StatusScheduled Installs, and per-extension Operations so you can see what the API actually did.
  • Deployment Log — every attempt, with user, environment, HTTP status, operation ID, and the raw response body.

Setup is a one-time job:

Step 1. Create the app registration

Go to the Azure portal, then Microsoft Entra ID > App registrations > New registration.


Step 2. Copy the Application (client) ID - you will paste this into Business Central

Step 3. Create a client secret

Go to Certificates & secrets > Client secrets > New client secret.


Step 4. Add API permissions

Go to API permissions > Add a permission > APIs my organization uses, and search for Dynamics 365 Business Central.

Choose Application permissions, and select the permission that grants admin center API access for your tenant.

Then select Grant admin consent for [tenant] and confirm. The Status column must show a green tick for every permission before you continue.


Step 5. Register the app in Business Central

In Business Central, use Tell Me to open Microsoft Entra Applications. Select New.

  • Client ID: paste the Application (client) ID from Step 2

 


Step 6. Assign Exten. Mgt. - Admin

On the same card, in the User Permission Sets subpage, add a line and select Exten. Mgt. - Admin.

State: set to Enabled

Step 7. Grant consent

Select Grant Consent on the Entra Applications page and complete the prompt with an account that can consent on behalf of the organization.

Step 8. Open the setup page

Open MPA Deploy Setup.


Step 9. Enter the credentials

In the Entra Application group:

  • Client ID: paste the Application (client) ID
  • Client Secret: paste the secret value from Step 3

Step 10. Test the connection

Select Test Connection.

The app requests a token, calls the installed apps endpoint on the target environment, and reports how many extensions came back. A number means authentication, permissions, and environment routing are all correct.

Step 11. Assign the permission set to users

Assign MPA Deploy Admin to the people who should be able to deploy. It is a standalone permission set and is not included in any Microsoft permission set, so nobody gets it by accident.

Step 12. Deploy a package

Open Installed Extensions (Admin Center) and Upload Extensions action.
Select Select Package, choose an .app file, decide whether to install now or wait for the update window, and select Deploy.



Step 13. Check the Installation Status

Open Installation Status action. Track the status to watch the install complete.

 



The source is on GitHub. Try it in a sandbox, tell me where it breaks, and open an issue if something is missing or wrong. Feature suggestions are just as welcome as bug reports.

https://github.com/pmohanakrishna/PTE-Extension-Management


Saturday, 12 September 2026

Pinned Comment Lines for Microsoft Dynamics 365 Business Central

An extension that makes important notes on customers, vendors, and items visible at the moment they matter, instead of hidden two clicks away.


The problem

Business Central already lets you record comments against a customer, a vendor, or an item. Someone careful writes down "always confirm the PO number before shipping" or "this customer disputes every invoice, copy the account manager", and the note is saved correctly.

Then nobody reads it.

Not because the note is wrong, but because of where it lives. Comments sit behind Customer > Comments, off the main card, on a page most users never open. The person picking and shipping the order has no reason to look there, and no indication that anything is waiting for them. The information is in the system; it simply isn't where the decision gets made.

What this extension does

It adds a single Pinned tick to the comment sheet you already use.

A pinned comment raises an on-screen notification whenever that customer, vendor, or item comes into play when the card is opened, when a sales or purchase document for them is opened, and when a pinned item is entered on a document line. The note travels to the point of work on its own.

Nothing about the existing comment functionality changes. This is not a replacement notes system: there is no new table, no separate editor, and no data to migrate. An existing comment becomes a pinned comment with one tick, and un-ticking it returns everything to normal.

Pinning a comment

1.  Open a customer, vendor, or item, and click Comments action.

2.  Write the comment exactly as you do today.

3.  Tick Pinned.

Three fields are added to the comment sheet:

Field

Purpose

Pinned

Marks the line to be raised as a notification.

Pin Until

Optional last date the note should appear. Leave blank to pin it indefinitely.

Pin Severity

Information for ordinary notes, Warning for notes that must not be missed.

 


Pinned lines are highlighted on the comment sheet itself, so it is obvious at a glance which notes are active, bold for Information, red for Warning.

Where the notification appears

Record

When it appears

Customer card

Every time the card is opened

Vendor card

Every time the card is opened

Item card

Every time the card is opened

Sales quote, order, invoice, credit memo, return order, blanket order

When the document is opened, and when the customer is entered

Purchase quote, order, invoice, credit memo, return order, blanket order

When the document is opened, and when the vendor is entered

Sales and purchase lines

When a pinned item is entered on the line

 


The notification reappears every time, not just the first time. If a user glances away or dismisses it, it will be there again the next time they open the record. A warning that shows once and then goes quiet is worse than no warning, because people assume they are covered.

What the notification says

All pinned comments for one record are combined into a single notification rather than one per line. Each pinned comment line appears as its own note, in comment sheet order, separated by a vertical bar:

Pinned comments (3): Always confirm the PO number before shipping | Delivery bookings need 48 hours notice | Invoices must quote the contract number

Longer messages are shortened to keep the banner readable, and blank lines are ignored. If any of the pinned lines is marked Warning, the whole notification is presented as a warning.

Every notification carries a Show comments action that opens the comment sheet filtered to that record, so the full text is always one click away.

Notes that expire on their own

Pin Until exists so temporary notes do not become permanent clutter. Set it to the date a note stops being relevant, the end of a promotion, the date a dispute is expected to close, the last day of a delivery embargo.

Once that date passes, the note simply stops appearing. Nothing needs to be tidied up, no error is raised, and the comment itself stays on the sheet as a record of what happened. Clearing the date or setting a later one brings it back.

Users stay in control

The notification is registered with Business Central's standard notification framework. Any user who does not want it can search for My Notifications and clear Pinned comment lines, alongside every other notification the system offers.

There is no separate setup page to find or learn, and no administrator involvement required. The notification is switched on by default.

Safe for automated processes

Notifications are shown only to users working in the client. Batch posting, job queue entries, API calls, and web service integrations are unaffected. A pinned comment never interrupts an automated process or causes it to fail.

No configuration is needed after installation. Existing comments are untouched until someone ticks Pinned.

At a glance

 

 

Applies to

Customers, vendors, items

Requires

Business Central 26 or later

Setup

None

New pages

None

Licence

MIT, free to use and modify

Source

https://github.com/pmohanakrishna/pinned-comment-lines

 

Friday, 11 September 2026

You can't see your stale documents, and that's why they're stale

Open the sales order list in Business Central and filter by date. Now do the same for quotes. Now for unposted invoices. Three lists, three filters, no way to see them together, and no way to answer the only question that matters in a Monday pipeline meeting: what is stale, and whose is it?

So the documents pile up. Quotes nobody chased. Orders shipped three weeks ago and never invoiced. Invoices sitting unposted since last month because the person who raised them went on leave. Every partner I've worked with has fielded this request, and the usual answer is a manual Excel pull that someone does once, shows in a meeting, and never does again.

I built Unposted Document Aging to replace that Excel pull with a page.

One list, aged into bands

The extension adds a single read-only list that pulls sales quotes, orders and unposted invoices and optionally purchase documents into one view, with the age of each document and the person who owns it.

The important part isn't the list. It's the bands.

A flat list of 400 stale documents gets opened once. An order created yesterday with nothing shipped is not a problem; an order fully shipped three weeks ago and never invoiced is money sitting on the floor. Those two things should not look the same on screen. So every row lands in one of six bands, sorted so the money is at the top:



Band

Rule

Shipped Not Invoiced

Order completely shipped, or with any line showing a shipped quantity

Quote Expired

Quote whose Quote Valid To Date has passed

Invoice Unposted

Unposted invoice older than the invoice threshold

Order Stale

Order past the order threshold with nothing shipped

Quote Stale

Quote past the quote threshold, not yet expired

Other

Fallback

Shipped Not Invoiced and Quote Expired are highlighted in red. Thresholds default to 30 days for quotes, 14 for orders and 7 for unposted invoices, and are configurable per company.


The argument you're going to have about dates

Here's the design decision that determines whether anyone trusts the page: which date defines "old"?

Document Date is what people mean when they say a quote is old. It is also backdated regularly, which is precisely why some people won't trust a report built on it.

Created uses the record's SystemCreatedAt and tells you when the document genuinely appeared in the system. Harder to argue with, less intuitive.

I made it a setup switch and defaulted to Document Date, because that's the one people will argue about in the meeting and they should be able to flip it and see both.

No stored data

The list is a temporary buffer built on demand by a codeunit, with the page bound to it using SourceTableTemporary. Nothing is stored. There's no job queue keeping a table warm, nothing to go stale, no upgrade code, and the numbers always reflect the live document tables. Hit Refresh and it rebuilds.

A query object can't union across Sales Header and Purchase Header, so the buffer was the only sensible route anyway but the absence of stored state turned out to be the best property of the design.

Performance was the thing I worried about most, since building a buffer from scratch on every page open is exactly how you write a slow app. What keeps it honest:

  • Every threshold is turned into a cutoff date in AL and applied as a SetFilter on the header, so SQL does the filtering. There is no loop over open documents testing ages in code.
  • One pass per document type, so each gets its own cutoff rather than a lowest-common-denominator filter.
  • SetLoadFields on both header loops.
  • Amount Including VAT is a FlowField, so CalcFields runs only on rows that already made it into the buffer never before filtering. There's a Calculate Amounts toggle to turn it off entirely on very large databases.

Amounts are converted to LCY so a mixed-currency list totals meaningfully, with the currency code kept for display. Choosing a document number opens the actual document, whatever type it is, via a stored RecordId.

The part that actually changes behaviour

A page helps the person who opens it. A digest helps everyone else.

The extension can email a daily digest, and the feature worth having is that it's per salesperson. Rows are grouped by salesperson code, each person's address is resolved from their Salesperson/Purchaser record, and each person gets only their own rows. A digest that goes to everyone gets filtered into a folder and ignored. One that says "you have 6 quotes over 30 days old" gets read.

Managers and shared mailboxes can be added as separate recipients, optionally filtered to a subset of salespeople. It sends through the modern email module with its own Email Scenario, so an admin can point it at a dedicated account on the Email Accounts page. One bad address doesn't abort the run, failures are collected and shown on the setup page. There's a button that creates the recurring job queue entry so nobody has to know a codeunit ID.


It's a per-tenant extension targeting BC 26 and later, and it compiles clean under CodeCop and UICop.

Source: https://github.com/pmohanakrishna/Unposted-Document-Aging

If you install it and the bands don't match how your team actually triages work, that's the most useful thing you could tell me.

Thursday, 10 September 2026

Managing Apps in the Business Central Admin Center

A BC environment is really a stack of apps: Base Application, Microsoft first-party apps, ISV apps, and your own per-tenant extensions (PTEs). The Manage Apps page in the admin center is where you keep all of that under control. Here's what it actually lets you do.



Getting there

Environments > select the environment > Apps. Use the dropdown to switch between Global, Per-Tenant Extension, and Dev Extension apps. Click an app name to open App Details for the actions on that specific app.

What you can do, by app type

App type

View

Upload

Install

Update

Uninstall

Global (marketplace)

Yes

No

No

Yes

Yes

Per-Tenant Extension

Yes

Yes

Yes

Yes

Yes

Dev Extension

Yes

No

No

No

Yes

The one to remember: you can't install a new global app from here, only update or uninstall one already on the environment. New global apps come from marketplace.microsoft.com (the site Microsoft used to call AppSource).

Per-tenant extensions

Choose Install Extension from Manage Apps or App Details:

1.      Select the .app file: BC figures out if it's new or an update.

2.      Pick a Deployment schedule (immediately, next update window, or next minor/major update: new PTEs only get the first two).

3.      Pick a Sync Mode. (Add or Force Sync)

4.      Confirm, and track progress on the Operations page.



A few rules to keep in mind:

  • Don't mix this with Extension Management in the client. Scheduled installs from one won't show in the other until they finish.
  • Extension Management is being phased out as an upload surface. Move PTE deployment to the admin center or the Admin Center API now, since Microsoft has said the client-side upload option is expected to go away in 2027 release wave 1.
  • You can queue different versions of the same PTE against different schedules, but not two versions against the same schedule.

Uninstalling an app

Test uninstalls in a sandbox copy of production first. You'll find the Uninstall action on Manage Apps or App Details; apps like Base Application that can't be removed show N/A.



Two things to watch:

  • You can choose to delete the app's data too. If you do, your only way back is a point-in-time restore (28 days), so export the database first if you need a longer safety net.
  • Dependent apps get uninstalled too, and BC will list them for you to confirm.




Quick checklist

  • Review Manage Apps on a schedule, not just when something breaks
  • Use the update window instead of pushing updates mid-day
  • Set Apps Update Cadence on purpose
  • Move PTE deployment off Extension Management now
  • Rehearse uninstalls in sandbox, and export data before any deletion
  • Always grab the Operation ID on a failed update