Today I’m releasing my ALBuild tool as open-source. ALBuild is a tool that can provide consistency when you need to produce app files for distribution. ALBuild can work as a standalone tool or triggered by build agents, check it out:

In this video, Erik announces the open-source release of ALBuild, a command-line build tool for Business Central AL development that he’s been using internally for years. He walks through what ALBuild does, how it’s configured via JSON files, demonstrates a full build pipeline completing in under 12 seconds, and showcases its built-in translation system powered by Azure Cognitive Services. The tool is now available on GitHub under the MIT license.
Background: Why ALBuild Exists
There are several ways to build AL apps for Business Central — Microsoft introduced AL-Go on GitHub, Waldo created AL-Ops, and there are likely others. When Erik started transitioning from C/AL to AL a long time ago, he took some of the tools he had for C/AL and transformed them into something usable for AL development. Over time, these pieces slowly evolved, and eventually he decided to bring them all together into a coherent tool.
Until now, ALBuild has been used exclusively by Erik himself and by eFocus and Hougaard. He considered retiring it in favor of AL-Ops or Microsoft’s GitHub-based tooling, but ultimately decided he liked what he’d created. So instead of shelving it, he cleaned it up and released it as open source under the MIT license — meaning anyone can use all of it, part of it, or incorporate it into their own toolchain.
What Is ALBuild?
First and foremost, ALBuild is a command-line tool. Whether you fire off commands manually, trigger them from a build agent, a webhook, or any other automation — it all works. You call ALBuild with a JSON configuration file, and it executes a series of tasks defined in that file.
The entry point is simple. Here’s the build command file:
@echo off
c:\projects\albuild\video\ALBuild.exe pos.json
That’s essentially a one-liner. You call ALBuild.exe and pass it a JSON file as a parameter. You could also pass an offline flag, which we’ll get to later. The JSON file contains all the instructions for what to do.
The Build Pipeline in Detail
Here’s the full JSON configuration file that drives the build process:
{
"Project": "Point of Sale",
"Report" : "Email",
"ReportDestination" : "erik@hougaard.com",
"Tasks": [
{
"Type": "DeployBasicDocker",
"Settings": {
"AppFile": "c:\\projects\\albuild\\testrunner\\Hougaard_ALBuild TestRunner_1.0.0.0.app",
"BaseURL": "http://bc20:7049/BC/",
"User": "demo",
"Password": "demo",
"SchemaUpdateMode": "forcesync"
}
},
{
"Type": "Git",
"Settings": {
"Path": "c:\\projects\\youtube\\point of sale",
"Command": "pull"
}
},
{
"Type": "UpdateVersion",
"Settings": {
"AppPath": "c:\\projects\\youtube\\point of sale",
"VersionPartToIncrement": 4,
"Increment": 1,
"DateInVersionPartNo": 3
}
},
{
"Type": "Remember",
"Settings": {
"AppPath": "c:\\projects\\youtube\\point of sale"
}
},
{
"Type": "DownloadSymbolsDocker",
"Settings": {
"AppPath": "%APPPATH%",
"BaseURL": "http://bc20:7049/BC/",
"User": "demo",
"Password": "demo"
}
},
{
"Type": "Compile",
"Settings": {
"AppPath": "%APPPATH%"
}
},
{
"Type": "Translate",
"Settings": {
"XLFPath": "%APPPATH%\\Translations\\%NAME%.g.xlf",
"ProductName": "%NAME%"
}
},
{
"Type": "Compile",
"Settings": {
"AppPath": "%APPPATH%"
}
},
{
"Type": "Copy",
"Settings": {
"From": "%APPPATH%\\%PUBLISHER%_%NAME%_%VERSION%.app",
"To": "C:\\Projects\\youtube\\ALbuild\\Release\\%PUBLISHER%_%NAME%_%VERSION%.app"
}
},
{
"Type": "Git",
"Settings": {
"Path": "%APPPATH%",
"Command": "add *"
}
},
{
"Type": "Git",
"Settings": {
"Path": "%APPPATH%",
"Command": "commit -a -m \"ALBuild Version %VERSION%\""
}
},
{
"Type": "Git",
"Settings": {
"Path": "%APPPATH%",
"Command": "push"
}
}
]
}
Let’s walk through each task and what it does.
1. DeployBasicDocker
The first task deploys an app to a Docker-based Business Central instance using basic authentication. In this example, it deploys a test runner app — a simple app that enables running a test codeunit. You provide a base URL for the Docker instance, username, password, and a schema update mode. This is a generic deployment function that can deploy any app: the app you’ve just built, library apps, or whatever is needed. There’s also a sibling command called DeploySaaS that uses OAuth instead of basic auth.
2. Git Pull
The next task is a Git command. ALBuild figures out where Git is located on your machine — as long as you have Git installed, it will find it. The output between the task name and “completed successful” is the actual output from Git. In this case, we pull the latest version before building.
3. UpdateVersion
This task reads the app.json file and updates the version number. Given a version like 1.0.0.0 with parts numbered 1 through 4, you can specify which part to increment. In this example, part 4 gets incremented by 1. There’s also an option to embed the date into a version part — here, part 3 gets the current date. You can skip the date option and just get a simple version increment.
4. Remember
The Remember function is a clever mechanism. You give it a path, and it does two things: it remembers the path (accessible as %APPPATH%), and it reads the app.json file at that location. All the content of the JSON file then becomes available as parameters you can reference later in the pipeline — things like %NAME%, %PUBLISHER%, and %VERSION%.
5. DownloadSymbolsDocker
This downloads the symbols for the app from a Docker instance. Notice how it uses %APPPATH% — the value remembered from the previous step. Erik notes that he’s actually in the school of not doing this normally, because at both Hougaard and eFocus they tag apps to a specific version for compatibility. To avoid “symbols pollution,” they keep the symbols from the oldest supported version. But the option is there if you need it, and there’s also a separate command to copy symbols from another location.
6. First Compile
ALBuild requires that you have the AL compiler installed via VS Code — it will search for it and find where it’s located. In this case, only the app path is specified. The first compile’s real purpose is to generate an up-to-date translation file (XLF) with all the texts that need translating.
7. Translate
This is where things get interesting. The translate task takes the XLF file path and translates the app. We’ll dive deeper into the translation system in the next section.
8. Second Compile
After translation, the app is compiled again — this time it’s the “real” compile that produces the final app file with translations included. A typical pipeline would also include a Sign command after this step if you have a code-signing certificate (required for AppSource deployment), but it’s not included in this example.
9. Copy
A straightforward file copy. It takes the compiled app file — using the Microsoft naming convention of Publisher_Name_Version.app — and copies it to a release folder. You could also copy to OneDrive or another destination. Erik mentions he was working on an FTP task but didn’t complete it in time for the release.
10–12. Git Add, Commit, and Push
The final three tasks handle Git operations: add all changed files, commit with a message that includes the version number pulled from the remembered app.json, and push to the remote repository.
All of this typically completes in under 12 seconds.
The Translation System
One of ALBuild’s most sophisticated features is its multi-layered translation system. It works on three levels:
- Local database: If the translation exists in a local SQLite database, it’s used immediately — ultra-fast with no network calls needed.
- Azure Table Storage (cloud): If the translation isn’t in the local database but exists in a shared cloud storage, it’s pulled from there. This is useful when you have multiple build machines — when Machine A translates something new, it stores the result both locally and in the cloud. When Machine B encounters the same text, it finds Machine A’s translation in the cloud instead of calling the translation API again.
- Azure Cognitive Services: If the text is completely unknown, it calls out to Azure’s translation service. The result is then stored both locally and in the cloud, so it only needs to be translated once across all machines.
The goal is that any specific text should never need to be translated more than once, regardless of how many build machines you have.
Translation Admin Tool
ALBuild ships with a Windows-based Translation Admin tool for managing translations. You can:
- Search for specific translations (use an asterisk for partial matching)
- Edit translations manually — corrections are saved to both the local database and the cloud
- Import XLF files to learn new translations
- Import from BC artifacts — this uses the same artifact source as BcContainerHelper. You specify a version (e.g., 20.2) and a language (e.g., Danish), and the tool downloads the artifact, extracts all apps, pulls out all translations, and imports them to both local and cloud databases
The artifact import feature is particularly powerful: if your app has a field called “Customer No.”, there’s no reason to have someone translate that manually because Microsoft has already translated it into every supported language. You’re standing on the shoulders of all the translation work Microsoft has already done. Erik mentions that his full translation database — covering most languages — is almost a gigabyte in size.
Standalone Translation and Offline Mode
The translation functionality is also available as a standalone tool called BC Translate, in case you only need the translation part without the full build pipeline.
The configuration lives in a .config file alongside each executable, where you specify:
- Azure Cognitive Services translation key
- Path to the local translation database
- Which languages to support
- Azure Storage account and key for cloud synchronization
If you don’t want the cloud-based translation features, you can pass the offline flag when running ALBuild. In offline mode, it will use translations from the local database if available, and skip anything it can’t translate locally.
Architecture and Extensibility
Erik deliberately kept things simple. Each task type is its own small class — for example, the Git task is only about 77 lines of code. It’s mainly a wrapper that finds Git on your machine and passes commands to it. Tasks don’t even use inheritance; they’re called via a straightforward case statement. This makes it easy to extend with new task types.
The executables are built to be self-contained, which makes them larger in file size but eliminates the need to install the .NET framework or other dependencies on the target machine.
Where to Find It
ALBuild is available on GitHub under the Hougaard organization, in a repository called albuild-open-source. You can also reach it via hougaard.com/albuild. Pre-built executables are available in the GitHub releases. The repository includes an examples folder with sample configurations, including more complex scenarios involving SaaS deployment and testing.
Summary
ALBuild is a fast, lightweight, command-line build tool for Business Central AL development that Erik has been using in production for years. Its key strengths are its speed (full builds in under 12 seconds), its JSON-driven pipeline configuration with variable substitution via the Remember mechanism, and its sophisticated three-tier translation system that minimizes redundant API calls. Released under the MIT license, it’s not positioned as a replacement for AL-Go or AL-Ops — it’s simply a tool that works well for Erik’s workflow and might work for yours too. Give it a try, file issues on GitHub, or better yet, fix things yourself and send a pull request.