Project configuration (albuild.json)
ALbuild has one developer-facing configuration file: albuild.json. It is committed to the repository and gives developers control over the build without touching pipeline YAML.
There are two scopes, merged with the app folder winning:
- Workspace root:
albuild.jsonat the repo root: shared defaults for every app. - App folder:
albuild.jsonnext to an app'sapp.json: per-app overrides (useful in a multi-root workspace such as separateappandtestapps).
Project config vs. machine config
This is separate from the machine/runtime settings managed by Get-ALbuildConfig / Set-ALbuildConfig (artifact/package cache folders, retry, telemetry, licensing). Those are per-machine, live machine-wide under C:\ProgramData\ALbuild\config.json, and are not committed.
Settings
| Key | Type | Default | Purpose |
|---|---|---|---|
country | string | w1 | Localisation of the BC target version. See BC target selection. |
artifactType | string | Sandbox | Sandbox or OnPrem. See BC target selection. |
bcVersion | string | (empty) | Explicit BC version or prefix; empty = newest matching. See BC target selection. |
select | string | Latest | Which build to pick when several match: Latest / First / Closest / NextMinor / NextMajor. See select strategies. |
testRunnerCodeunitId | int | 0 | Test-runner codeunit id; 0 = the isolation default. See Test settings. |
testSuite | string | DEFAULT | Name of the test suite to run in the container. See Test settings. |
disableTestIsolation | bool | false | Run tests without test isolation (uses runner 130451). See Test settings. |
feeds | array | [] | NuGet dependency feeds (URL strings or objects. See Feeds). |
universalPackages | array | [] | Azure DevOps Universal-feed dependency packages. See Dependency sources. |
localPackages | array | ['.dependencies'] | Repo folders of committed .app dependencies. See Dependency sources. |
urlPackages | array | [] | .app dependencies served from a direct download link. See Dependency sources. |
excludeProjects | array | [] | Folder names to skip in the multi-root build. See Multi-root workspaces. |
analyzers | array | [] | AL code analyzers to run during compile. See Code analysis. |
ruleSet | string | (empty) | Path to a .ruleset applied to those analyzers. See Code analysis. |
licenseFile | string | (empty) | BC license for the build container, as a path or URL. See Build container license. |
translation | object | (defaults) | XLIFF sync and translation-quality settings. See Translation. |
When testRunnerCodeunitId is 0, the effective runner is 130450 (test isolation) or, when disableTestIsolation is true, 130451.
BC target selection
country, artifactType, bcVersion and select together decide which Business Central build the app is compiled, published and tested against. They are read by the Get BC Artifact task / Find-BcArtifactUrl (an explicit task input always overrides the config value).
-
country— the localisation of the target build.w1is the base (worldwide) build; a country code such asde,fr,us,nl,ch, … selects the localized build, which carries that country's regulatory objects (e.g. the German Delivery Reminder / Liefermahnung). Use the country your app ships to, orw1for a country-neutral app. -
artifactType— which artifact family to download:Value Meaning SandboxThe cloud/sandbox artifact (the default). Matches the SaaS platform; use it for AppSource apps and cloud targets. OnPremThe on-premises artifact. Use it when the customer runs BC on-prem (a fixed released build) and for a localized on-prem target — the on-prem artifact carries the full country-specific first-party set. -
bcVersion— pins the build. Accepts a full version (26.3.36158.36321), a prefix (26,26.3), or is left empty to take the newest build that matchescountry/artifactType. Combine withselectto control how a prefix (several matching builds) is narrowed to one.
select strategies
When more than one build matches country/artifactType/bcVersion, select decides which one wins:
| Value | Picks |
|---|---|
Latest (default) | The newest matching build. The normal choice — always builds against the most recent patch. |
First | The oldest matching build. Useful to test against the minimum build a bcVersion prefix still covers. |
Closest | The lowest build ≥ bcVersion, otherwise the newest. bcVersion must be a full version (1.2.3.4). Use it to land on an exact target build (or the next available one) — e.g. to match a customer's installed build. |
NextMinor | The next minor insider (pre-release) build. Requires Microsoft Insider access / EULA acceptance; for early compatibility testing only, not for release builds. |
NextMajor | The next major insider (pre-release) build. Same insider prerequisite as NextMinor. |
Example: on-prem, localized, pinned to one build
A German on-premises target fixed to one released version:
Code
Test settings
testRunnerCodeunitId, testSuite and disableTestIsolation are read by the Run AL Tests task / Invoke-BcContainerTest, resolved per app.
testRunnerCodeunitId— the id of the test-runner codeunit to drive the tests with.0(the default) means use the isolation default:130450when tests run with test isolation, or130451whendisableTestIsolationistrue. Set a specific id only to use a custom runner.disableTestIsolation— whentrue, tests run without database test isolation (each test's data changes are not rolled back). Defaults tofalse(isolation on, runner130450);trueswitches the default runner to130451.testSuite— the name of the test suite to execute inside the container. Defaults toDEFAULT.
Dependency sources
Dependencies are resolved from four kinds of source and all land in each project's .alpackages (used for compilation and then installed into the build container in dependency order):
- NuGet feeds (
feeds), resolved transitively by app id (Continia, 365bd, SIMOVA/nuget.org, DYCE via a private feed with anapiKeyVariablekey, …). See Feeds. - Universal packages (
universalPackages), named packages from an Azure DevOps Universal feed (e.g. apps you publish to aProductsfeed). The build downloads them with the pipeline'sSystem.AccessToken;organizationdefaults to the collection URI andprojectto the running project. - Local packages (
localPackages), repository folders of committed.appfiles, for ISVs with no public feed. Defaults to.dependencies; paths are relative to the repo root. - URL packages (
urlPackages),.appfiles served from a direct download link (an ISV that publishes a link rather than a feed, e.g. bms GmbH's b-jira). Each entry is a URL string or{ url, tokenEnv?, header? }.
Source precedence: localPackages/urlPackages → feeds → universalPackages. An app provided locally or by URL is authoritative — it is pinned and used even when a feed offers a newer version. Feeds take precedence over universal packages (a universal copy is only a fallback for apps no feed provides). A committed encrypted runtime .app whose app id ALbuild cannot parse on the host is pinned by its {Publisher}_{Name}_{Version}.app file name and installed from localPackages; it is also copied into .alpackages, where both the host and the container compiler resolve against it, so no separate symbol package is needed. See source precedence for the full rules.
Code
Real apps vs. symbol-only
A dependency must come from a source that ships the real app (not symbol-only) if the build installs it to run tests; symbol-only packages can be compiled against but are skipped at install.
Multi-root workspaces
A repository may contain several AL projects side by side (e.g. app, test, migration). With an empty projectFolder the pipeline builds all of them, in dependency order (a project is compiled, published and installed after the in-repo projects it depends on, so app before its test/migration), sharing one container. Each project's compiled .app is copied into its dependents' .alpackages so they compile against it.
Order is derived from each app.json's id/dependencies (see Get-BcProjectBuildOrder). To skip a project, list its folder name in excludeProjects (repo-root albuild.json) and/or the excludeProjects pipeline parameter (comma-separated); the two are merged.
Code
Feeds
Declare the NuGet feeds your dependencies come from once in albuild.json instead of repeating Register-BcFeed in every pipeline. Resolve-BcDependencies reads them automatically (and Register-BcFeed -FromProjectConfig <folder> registers them explicitly if you prefer).
Each entry is either a URL string or an object. Only url is required:
| Field | Required | Default | Purpose |
|---|---|---|---|
url | yes | The NuGet v3 service index (.../index.json). | |
name | no | derived from the URL | A unique feed name. |
kind | no | apps | apps / runtime / symbols. Rarely needed. See below. |
idScheme | no | {publisher}.{name}.{id} | Package-id template. Rarely needed. See below. |
apiKey | no | (none) | Access key / PAT for a private feed, inline; supports a ${env:NAME} placeholder. |
apiKeyVariable | no | (none) | Name of an environment variable holding the access key (keeps it out of the file). |
token/tokenEnvare still accepted as aliases forapiKey/apiKeyVariable.
Keep secrets out of the file
Prefer naming an environment variable with apiKeyVariable (or a ${env:NAME} placeholder in apiKey). An inline apiKey is supported for convenience but commits the secret, so don't use it in a tracked albuild.json. If both are given, the inline apiKey wins.
kind and idScheme are almost never needed. The resolver auto-detects runtime/indirect ("metapackage") packages from their NuGet metadata and locates packages by app id via the feed's search service, so it copes with feeds whose ids carry a .runtime. infix or whose publisher/name segments differ from your app.json. Set them only to override an edge case.
Code
With the above, the whole dependency step is just:
Code
Explicitly passed -Feeds (or feeds already registered with Register-BcFeed) still take part; the config feeds are added, not a replacement.
Code analysis
analyzers names the AL analyzers to run during compilation, and ruleSet points at a .ruleset
file applied to them. Setting them in albuild.json means the pipeline and your editor agree on
what "clean" means, without repeating the list in YAML.
Code
Analyzers are given by token or short name (CodeCop, UICop, AppSourceCop,
PerTenantExtensionCop, with or without the ${...} wrapper), or as an explicit path to an
analyzer DLL. An empty list means no analyzers.
Precedence, highest first: an explicit Compile AL App task input, then albuild.json, then
the project's .vscode/settings.json (al.codeAnalyzers / al.ruleSetPath). So an existing VS
Code setup keeps working, and albuild.json overrides it when you want the build to be stricter.
Build container license
The artifact's built-in Cronus demo license is enough for most builds, but it is restrictive in
ways that break real test suites, most commonly its posting-date interval
(??11*|??12*|??01*|??02*), which fails any date-dependent test outside those months. Point
licenseFile at your own license to replace it. The value is passed to
New-BcContainer -LicenseFile and may be a path
or a URL.
Keep the license out of source control
albuild.json is committed, so do not put a license path that only exists on your machine, and
never commit the license itself. Use a ${env:NAME} placeholder, resolved exactly like feed
tokens:
Code
Translation
The optional translation block controls XLIFF synchronisation and translation quality. Omit it
and ALbuild uses sensible defaults: the target languages are taken from the project's existing
*.??-??.xlf files, translation memory draws on the project itself plus the BC base application,
and the pipeline mode is write locally but check in CI (ALBUILD_CI=1), so a build never
silently rewrites translations on the agent.
Code
| Field | Purpose |
|---|---|
targetLanguages | Languages to maintain. Default: the languages of the existing *.??-??.xlf files. |
pipelineMode | write updates the XLIFF files, check fails on drift without writing, off skips the step. |
failOnMissing | Fail when a translation unit has no translation. |
memory.enabled | Use translation memory to pre-fill units. |
memory.contextAware | Weight memory hits by the unit's context, not just its source text. |
memory.sources | Ordered sources. kind is self (this project), bc-base (the Business Central base application) or xlf (a path you provide); priority breaks ties. |
Who reads it
- Get BC Artifact task /
Find-BcArtifactUrl,country,artifactType,bcVersion,select(explicit task inputs still win). - Run AL Tests task /
Invoke-BcContainerTest,testRunnerCodeunitId,testSuite,disableTestIsolation, resolved per app. - Compile AL App task /
Invoke-BcCompiler,analyzers,ruleSet. - Create BC Container task /
New-BcContainer,licenseFile. - Resolve Dependencies task /
Resolve-BcDependencies,feeds,universalPackages,localPackages,urlPackages. - The translation commands, the
translationblock.
In code, Get-ALbuildProjectConfig -AppFolder <app> -WorkspaceRoot <repo-root> returns the merged configuration.
Deprecated pipeline.config
The ALbuild V1 pipeline.config file is still read as a fallback when no albuild.json is present in a folder. Its alTestRunnerId maps to testRunnerCodeunitId. A deprecation warning is logged, rename the file to albuild.json.


