Email this post as a PDFDevelopment · 7 October 2026 · 3 min read

Codeunit design: single responsibility, facades, and what "Mgt." should mean

A codeunit is a container for procedures and nothing stops you putting everything in one. The base application has a few conventions that keep its thousands of codeunits navigable, and they apply equally to a per-tenant extension. How to decide what goes in which codeunit, the facade pattern the System Application uses, local versus internal versus public, and the three codeunits every extension has.

Contents
  1. One responsibility per codeunit
  2. What "Mgt." should mean
  3. The facade pattern
  4. Access levels
  5. The three codeunits every extension has
  6. Single instance
  7. Smells

Codeunit design is where an extension is either readable in a year or not. The platform does not care; the next developer does. These are the conventions that make the base application navigable and that we apply to every extension.

One responsibility per codeunit

A codeunit is named for what it does to what: "CON Courier Shipment Mgt." manages shipments (create, release, cancel); "CON Courier API Client" talks HTTP; "CON Courier Label Printer" renders labels. When a codeunit has procedures about two different things, it is two codeunits. When a procedure is three hundred lines, it is several procedures. The test: can you say in one sentence what this codeunit is responsible for, without "and"?

What "Mgt." should mean

The base application's "Sales Header Mgt.", "Item Tracking Management", "DimensionManagement": a management codeunit is the business operations on an entity, the verbs a user or another codeunit calls (Release, Reopen, Archive, Copy). It is the public face of the entity. It is not a dumping ground for utilities, and it does not do HTTP, file handling or UI; those are their own codeunits that Mgt. calls.

The facade pattern

The System Application exposes each module through one public codeunit (the facade: Email, "Temp Blob", "No. Series") and keeps the implementation in Access = Internal codeunits behind it. Callers only see the facade; Microsoft can rewrite the implementation without breaking anyone. Do the same for any area of your extension that other apps, or other parts of your own app, call: one public codeunit with a small, documented surface, and everything else internal.

codeunit 50100 "CON Courier"          // facade, Access = Public
{
    procedure Send(var Shipment: Record "CON Courier Shipment")
    var
        Impl: Codeunit "CON Courier Impl.";
    begin
        Impl.Send(Shipment);
    end;
}

codeunit 50101 "CON Courier Impl."     // Access = Internal
{
    internal procedure Send(var Shipment: Record "CON Courier Shipment")
    ...
}

Access levels

  • local: callable only within the codeunit. The default for everything.
  • internal: callable within the app (and apps in internalsVisibleTo). For implementation shared across your codeunits.
  • public (no modifier): callable by anyone, including other apps, forever. Every public procedure is a contract you maintain; make it deliberate and mark it [Obsolete] before you change it.

The three codeunits every extension has

  • Install (Subtype = Install): first-time setup, registering upgrade tags, default data, retention policy registration.
  • Upgrade (Subtype = Upgrade): data moves between versions, guarded by tags (upgrade post).
  • Event subscribers: one per base codeunit or area you extend, thin, calling your Mgt. codeunits.

Single instance

SingleInstance = true makes a codeunit's global variables live for the session. Use it for caches and flags (the "GetRecordOnce" pattern, a "suppress event during import" flag). Do not use it for state that should be per operation; it leaks between calls in the same session.

Smells

  • A codeunit called "CON Utilities" or "CON Helpers" with forty unrelated procedures.
  • Pages calling three codeunits in sequence to do one thing (that sequence is a Mgt. procedure).
  • A public procedure with eight parameters (pass a record or a temporary record).
  • Business logic in an event subscriber (events post).
Email this post as a PDF
A branded PDF of this post, sent to your inbox to keep, print or share. Copy in colleagues if you like.
We only use these addresses to send this PDF. Nobody is added to a mailing list. Mike at Business Boxed receives a copy. See our privacy notice.
Email this post
Talk to us
Want this done in your Business Central?
Book a 30 minute callGet the monthly newsletter

Related posts