// article
Every public AL symbol is a promise to dependent extensions. Once another app compiles against a table, codeunit, field, query, procedure, or interface, changing that symbol can turn an internal refactor into a customer upgrade failure.
Access modifiers and explicit dependencies let an extension publisher control that promise. They do not replace permissions or data security; they shape the compile-time API surface.
The AL Access property applies to codeunits, queries, tables, table fields, enums, interfaces, and permission sets. Microsoft documents two values for objects, plus two more that are available only on table fields:
public: accessible from the same module and dependent modules; it is the default when Access is omitted.internal: accessible inside the same module, with controlled test/friend access through internalsVisibleTo.protected: a table-field-only value; the field can be accessed only by code in the same table or in table extensions of that table.local: a table-field-only value; the field can be accessed only by code in the same table or table extension where the field is defined.Start new implementation objects as internal unless a documented consumer needs them. Make a symbol public only with a name, behavior, error contract, and compatibility policy that the team is willing to support.
Microsoft explicitly states that AL access modifiers are compile-time controls, not a security boundary. Reflection-style mechanisms can still reach data at runtime. Protect business data with entitlements, permission sets, object permissions, security filters where appropriate, and application validation.
A dependent app that writes directly to an implementation table bypasses invariants and makes schema refactoring difficult. Prefer a focused public codeunit or interface that expresses the supported operation. Keep storage, orchestration, and helper code internal.
Interfaces reduce dependency on implementation details and enable multiple codeunit implementations. Microsoft advises keeping interfaces focused and avoiding incompatible additions to already-published interfaces. When a contract needs new mandatory behavior, publish a new interface version or a compatible extension pattern rather than silently breaking implementers.
An app dependency in app.json identifies the publisher, name, app ID, and minimum version of another extension. The minimum version is an operational statement: it tells Business Central which dependency release supplies the required contract.
Do not raise minimum versions without a reason, because that can force a dependency upgrade for every customer. Do raise them when the app genuinely uses a symbol or behavior introduced later. Microsoft's library/dependency app guidance notes that a dependency is automatically updated when the consuming app requires a higher minimum version.
For each public contract, define changes as:
A breaking change should use a new contract version, an obsoletion period where possible, migration notes, and coordinated testing with dependent apps.
An access modifier determines which AL code can reference a symbol when extensions compile. It does not decide whether a user can read a table, execute a page, or perform a business action at runtime. Those controls still belong in permission sets, entitlements where applicable, and the authorization checks of the business workflow.
This separation prevents a dangerous review mistake. A public procedure is not automatically available to every user, and an internal procedure is not automatically secure. Review the extension contract and the runtime permission model as two connected but independent layers, then test both with the identities that will operate the app.
For every public object or procedure, ask: who consumes it, what behavior is guaranteed, how is it authorized, how will it evolve, and how is it tested? If there is no clear consumer, it probably belongs behind an internal boundary.
Bitta Apps can review extension boundaries, refactor shared libraries, and establish compatibility checks through Business Central AL development, with release support for customer and Marketplace dependency chains.