2.3: Multi-Root Workspaces & Project Dependencies

Key Takeaways

  • Visual Studio Code multi-root workspaces (.code-workspace) allow developers to manage, edit, and compile multiple interdependent AL extension projects within a single unified IDE window.
  • The AL Language extension resolves symbols across open workspace folders directly in memory before querying the .alpackages folder, providing real-time cross-project IntelliSense without manual symbol downloads.
  • Extension dependencies are declared in app.json using id, name, publisher, and version, establishing a minimum version constraint (>= declared version) and determining build order.
  • Circular dependencies between AL extensions are strictly prohibited and fail the build; they must be resolved by refactoring shared models and interfaces into a lower-tier Core extension.
  • Workspace-level settings such as al.packageCachePath centralize symbol storage to a single shared directory, eliminating redundant multi-gigabyte symbol downloads across projects.
Last updated: August 2026

2.3: Multi-Root Workspaces & Project Dependencies

Enterprise Business Central solutions rarely consist of a single monolithic extension. Instead, professional development architectures partition complex business domains into modular, layered applications—such as core frameworks, domain-specific modules, country localizations, and integration connectors. The MB-820 exam tests your mastery of Visual Studio Code multi-root workspaces, project dependency resolution, circular reference elimination, and symbol cache optimization across multi-app architectures.


1. Multi-Root Workspace Architecture (.code-workspace)

A Visual Studio Code multi-root workspace enables developers to open and work on multiple distinct AL extension project folders simultaneously within a single IDE window. Each folder maintains its own independent app.json, launch.json, and source code tree, while sharing unified workspace settings.

{
  "folders": [
    {
      "name": "01 - Contoso Core Library",
      "path": "./ContosoCore"
    },
    {
      "name": "02 - Contoso Logistics Engine",
      "path": "./ContosoLogistics"
    },
    {
      "name": "03 - Contoso Shipping Connector",
      "path": "./ContosoShipping"
    }
  ],
  "settings": {
    "al.packageCachePath": "./.shared-packages",
    "al.enableCodeActions": true,
    "al.incrementalBuild": true,
    "al.codeAnalyzers": [
      "${CodeCop}",
      "${AppSourceCop}"
    ],
    "al.ruleSetPath": "./ruleset.json"
  }
}

In-Memory Abstract Syntax Tree (AST) Symbol Resolution

The primary benefit of multi-root workspaces is real-time in-memory symbol resolution:

  1. In a single-project setup, whenever an upstream dependency is modified, developers must recompile the upstream project (Ctrl+Shift+B), copy its generated .app package into the dependent project's .alpackages folder, and reload the window.
  2. In a multi-root workspace, the AL Language extension inspects all open workspace folders. When Project B depends on Project A, the language server constructs an in-memory Abstract Syntax Tree (AST) of Project A directly from its raw source code.
  3. Instant Cross-Project IntelliSense: If a developer adds a new public procedure or table field in ContosoCore, that procedure or field is immediately visible in ContosoLogistics and ContosoShipping via IntelliSense without compiling, packaging, or downloading symbols.

2. Project Dependencies & Dependency Graphs

Upstream dependencies are formally declared within the dependencies array of the downstream project's app.json:

{
  "id": "3d4e5f6a-7b8c-9d0e-1f2a-3b4c5d6e7f8a",
  "name": "Contoso Logistics Engine",
  "publisher": "Contoso",
  "version": "2.0.0.0",
  "dependencies": [
    {
      "id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
      "name": "Contoso Core Library",
      "publisher": "Contoso",
      "version": "1.5.0.0"
    }
  ]
}

Key Dependency Rules for the MB-820 Exam

  1. Exact Identification: A dependency entry requires four exact attributes: id (GUID), name, publisher, and version. The id is the primary matching key.
  2. Minimum Version Semantics: The version specified in the dependency declaration represents the minimum compatible version. The target runtime environment must have a version installed that is greater than or equal to (>=) the declared version (e.g., 1.5.0.0 or higher).
  3. Directed Acyclic Graph (DAG) Compilation Order: The AL compiler builds a dependency graph across all workspace folders. Compilation occurs strictly from the bottom up:
    • Level 0: Foundation / Core libraries (no dependencies).
    • Level 1: Domain modules (depend on Level 0).
    • Level 2: Composite integrations / UI customizations (depend on Level 1 and Level 0).
  4. Breaking Changes Propagation: If a developer modifies a public method signature (e.g., adding a mandatory parameter) or removes a table field in a Level 0 project, all downstream projects will immediately display compiler errors in the Problems pane until updated.

3. Circular Dependencies & Decoupling Strategies

A circular dependency occurs when Extension A depends on Extension B, while Extension B simultaneously depends on Extension A (either directly or transitively through an intermediary Extension C).

  FATAL ARCHITECTURAL DEFECT (Circular Dependency):
  +-----------------------+              +-----------------------+
  |     Extension A       | -----------> |      Extension B      |
  | (Contoso Logistics)   | <----------- | (Contoso Billing)     |
  +-----------------------+              +-----------------------+
  
  REFACTORED CLEAN ARCHITECTURE (Common Kernel / Interface Pattern):
  +-----------------------+              +-----------------------+
  |     Extension A       |              |      Extension B      |
  | (Contoso Logistics)   |              | (Contoso Billing)     |
  +-----------------------+              +-----------------------+
              \                              /
               \                            /
                v                          v
              +------------------------------+
              |         Extension C          |
              |   (Contoso Core Interfaces)  |
              | - Shared Tables & Enums      |
              | - Business Event Publishers  |
              +------------------------------+

Circular Dependency Detection

The AL compiler strictly forbids circular references. If a circular loop exists in the dependency graph, symbol resolution fails and the compiler reports that a circular dependency was detected between the listed extensions.

Architectural Remediation Patterns

When two modules require mutual interaction, developers must decouple them using one of two proven design patterns:

  1. Shared Kernel / Common Core Pattern:
    • Extract the shared tables, enums, interfaces, and integration event publishers into a third foundational extension (e.g., Contoso Core Interfaces).
    • Configure both Extension A and Extension B to depend downward on the Core extension.
  2. Event-Driven Decoupling (Publish/Subscribe):
    • Instead of Extension A directly invoking a codeunit in Extension B, Extension A declares and raises an Integration Event Publisher.
    • Extension B subscribes to Extension A's event using [EventSubscriber].
    • Extension A remains completely unaware of Extension B, eliminating the dependency from A to B.
  3. Interface Polymorphism:
    • Declare an AL interface in the Core extension.
    • Implement the interface within concrete codeunits in Extension A and Extension B.
    • Use extensible enums to dynamically instantiate the desired implementation at runtime without direct project coupling.

4. Centralized Package Cache Optimization (al.packageCachePath)

In enterprise multi-app workspaces containing multiple projects, each project by default maintains its own local .alpackages folder. Downloading identical multi-gigabyte symbol files (Microsoft_Base Application.app, Microsoft_System.app) for 5 to 10 distinct folders wastes gigabytes of disk space and saturates network bandwidth.

{
  "settings": {
    "al.packageCachePath": "c:/AL/SharedSymbols"
  }
}

Benefits of Centralized Package Caching:

  • Single Download: When AL: Download Symbols is executed in any project, symbols are downloaded to the centralized folder and immediately shared across all workspace projects.
  • Disk Footprint Reduction: Reduces workspace disk consumption from ~15 GB down to ~3 GB.
  • Fast CI/CD Builds: Build scripts can pre-populate the shared symbol directory once prior to executing parallel project builds.
  • Unified Cache Invalidation: Executing AL: Clear Object Cache flushes the single shared cache, preventing subtle version drift between projects.
Loading diagram...
Multi-Root Workspace Architecture & Symbol Dependency Resolution
Test Your Knowledge

A developer opens a multi-root workspace in Visual Studio Code containing two AL projects: 'AppCore' and 'AppExtension'. 'AppExtension' declares a dependency on 'AppCore' in its app.json. The developer adds a new global procedure to a codeunit in 'AppCore'. Without running 'AL: Package' or downloading symbols, the developer types the procedure name inside 'AppExtension' and IntelliSense immediately suggests it. Why does this occur?

A
B
C
D
Test Your Knowledge

During a code review, an AL architect identifies that 'Extension Sales' declares a dependency on 'Extension Inventory', while 'Extension Inventory' simultaneously declares a dependency on 'Extension Sales' in its app.json. When compiling the workspace, the AL compiler reports a circular dependency between the two extensions. What architectural pattern must be implemented to resolve this error?

A
B
C
D
Test Your Knowledge

In an AL extension's app.json manifest, the dependencies array contains the following entry: "dependencies": [ { "id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d", "name": "Contoso Core", "publisher": "Contoso", "version": "3.2.0.0" } ] What requirement does this dependency specification impose during compilation and deployment?

A
B
C
D
Test Your Knowledge

An enterprise development team maintains a multi-root workspace containing 8 interrelated AL extensions. Each developer experiences slow build times and high disk usage because each project downloads redundant 2 GB Base Application symbol files into its local .alpackages folder. How should the team optimize this configuration in the .code-workspace file?

A
B
C
D