Controls visibility of AL objects and fields using Access property (Public, Internal, Protected, Local), hides internal helpers from external apps, exposes public API surfaces, and configures internalsVisibleTo for multi-app scenarios. Use when making codeunits private, hiding staging tables, protecting fields from partners, or sharing internals between companion apps.
69
83%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
internalsVisibleTo apps can access internal objectsNote: BC 2019 Wave 2+ (Runtime 4.0). Compile-time only - RecordRef/FieldRef bypass at runtime.
Output: Objects with correct Access property, app.json with internalsVisibleTo (if multi-app).
Supported objects: Codeunit, Table, Table field, Query, Enum, Interface, PermissionSet
// Internal table - hidden from external apps
table <ID> "<PREFIX> Internal Staging"
{
Access = Internal;
// ... fields
}
// Internal codeunit - helper not exposed to partners
codeunit <ID> "<PREFIX> Internal Helper"
{
Access = Internal;
// ... procedures
}table <ID> "<PREFIX> Order Extension"
{
Access = Public;
fields
{
field(1; "Order No."; Code[20]) { Access = Public; } // Stable API
field(2; "Processing Flags"; Integer) { Access = Internal; } // Same app only
field(3; "Extension Point"; Code[50]) { Access = Protected; } // Table extensions
field(4; "Internal Counter"; Integer) { Access = Local; } // This table only
}
}| Level | Same Table | Table Extension | Same App | Other Apps |
|---|---|---|---|---|
Local | ✓ | |||
Protected | ✓ | ✓ | ||
Internal | ✓ | ✓ | ✓ | |
Public | ✓ | ✓ | ✓ | ✓ |
Designer note: Only Public fields appear in in-client Designer.
In app.json of the core app:
{
"internalsVisibleTo": [
{ "id": "<companion-app-guid>", "name": "Companion App", "publisher": "My Publisher" },
{ "id": "<test-app-guid>", "name": "Test App", "publisher": "My Publisher" }
]
}Use cases: Core + Companion apps, Test apps accessing internals, Modular architecture.
⚠️ NOT a security boundary: Access is compile-time only. RecordRef/FieldRef bypass at runtime. Use permission sets for data security.
codeunit <ID> "<PREFIX> Public API"
{
Access = Public;
procedure ProcessOperation(InputData: Text): Boolean
begin
exit(InternalProcessor.DoProcess(InputData));
end;
var
InternalProcessor: Codeunit "<PREFIX> Internal Processor";
}
codeunit <ID+1> "<PREFIX> Internal Processor"
{
Access = Internal;
procedure DoProcess(InputData: Text): Boolean
begin
// Can be refactored freely - not exposed
end;
}codeunit <ID> "<PREFIX> Secret Manager"
{
Access = Internal;
[NonDebuggable]
procedure GetClientSecret(): Text
begin
// Use IsolatedStorage with DataScope::Module
end;
}| Scenario | Recommended Access |
|---|---|
| Stable API for partners | Public |
| Helper codeunits | Internal |
| Staging/buffer tables | Internal |
| Fields for table extensions | Protected |
| Fields in table triggers only | Local |
| Secret management | Internal + [NonDebuggable] |
Guidelines: Default to Internal • Public = supported contract • Changing Public → Internal is breaking
Limitations: Cannot set on Pages, Reports, XMLports, Control add-ins.
52f8705
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.