In this video, I show my homegrown solution to build Business Central apps. ALBuild is a system that handles Git, translation, compilation, deployment, testing, signing and more, check out the video:

In this video, Erik demonstrates ALBuild — his custom command-line tool for building, testing, and deploying Business Central apps. He walks through a complete build process that compiles apps, handles translations, signs the output, deploys to Docker, runs tests, and commits everything to Git — all in under 40 seconds. He also shows the JSON configuration file that drives the entire pipeline and peeks at the C# source code behind it.
Why Build a Custom Build Tool?
Erik started building ALBuild when AL first came out for Business Central. At the time, there weren’t many CI/CD tools available for AL development, and he needed a consistent way to get apps published to AppSource. What began as a personal helper to remember all the necessary build steps evolved over time into a flexible command-line tool.
There are plenty of CI/CD tools out there — Erik mentions Baldo’s AL-OPS as one example — but for his workflow as a solo developer, ALBuild fits perfectly. He doesn’t need build servers running in the cloud or the overhead of waiting for scheduled builds on remote machines. With Docker containers running locally on his PC, he gets fast, reliable builds right from the command line.
The Build Process in Action
ALBuild is invoked via a simple batch file:
@echo off
c:\projects\albuild\video\ALBuild.exe pos.json
That’s it — call the ALBuild executable and pass it a JSON configuration file. The JSON file defines the project and an ordered list of tasks to execute. Each task must succeed before the next one runs.
In the demo, Erik builds an app that actually consists of two separate apps (a compiler app and a UI app). Here’s the full sequence that ALBuild executes:
- Deploy Test Runner — Deploys a test runner app to the Docker container. If it’s already installed at the same version, ALBuild recognizes the “unprocessable entity” error and treats it as a success.
- Git Pull — Pulls the latest changes from the repository.
- Update Version — Increments the version number in
app.json(e.g., from 1.0.0.69 to 1.0.0.70). - Remember — Stores the app’s metadata (path, name, publisher, version) so subsequent tasks can use substitution variables instead of hardcoded paths.
- First Compile — Compiles the app to generate the translation input (the .g.xlf file).
- Translate — Runs the translation process, checking existing translations and generating target language files.
- Second Compile — Recompiles with the translations included.
- Sign — Code-signs the compiled .app file.
- Deploy to Docker — Deploys the app using basic authentication to a local Docker container.
- Run Tests — Executes test codeunits against the deployed app in a specified company.
- Copy Artifacts — Copies the .app file to a release folder.
- Repeat for second app — The entire process repeats for the UI app with its own version tracking.
- Git Add, Commit, Push — Stages all changes (updated app.json files, translations, etc.), commits, and pushes to the private GitHub repo.
The entire process for both apps completed in approximately 37 seconds.
The JSON Configuration File
One of Erik’s design choices was to use JSON instead of YAML — he’s never had much love for YAML’s syntax, and since he was building his own tool, he was free to choose. Here’s the configuration file for the Point of Sale app demo:
{
"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"
}
}
]
}
Key Structure
The JSON file has a straightforward structure:
- Project — The project name.
- Report / ReportDestination — When the build completes, ALBuild can send a report via email (or save it to a file).
- Tasks — An ordered array of tasks. Each task has a
Typeand aSettingsobject whose fields vary depending on the task type.
The Remember Command and Substitution Variables
The Remember task is one of the more clever features. Once you tell ALBuild to remember an app path, it reads the app.json at that location and makes all of the app’s metadata available as substitution variables:
%APPPATH%— The root folder of the app%NAME%— The app name from app.json%PUBLISHER%— The publisher%VERSION%— The current version number
This means that if you rename your app or the version changes, the build file still works correctly. You can see this in action with the app file path: %APPPATH%\\%PUBLISHER%_%NAME%_%VERSION%.app — rather than hardcoding paths that would break with every version bump.
Available Task Types
From the video and configuration files, ALBuild supports the following task types:
- DeployBasicDocker — Deploy an app to a Docker container using basic authentication
- DeploySaaS — Deploy to a cloud sandbox using service-to-service (AAD app) authentication with client ID, secret, and tenant
- Git — Execute Git commands (pull, add, commit, push)
- UpdateVersion — Increment a specific part of the version number in app.json
- Remember — Store app metadata for use as substitution variables
- DownloadSymbolsDocker — Download symbols from a Docker container
- Compile — Compile the AL app
- Translate — Run the translation process on XLF files
- Sign — Code-sign the .app file with a certificate
- TestBasicDocker — Run test codeunits against a Docker container
- Copy — Copy files (typically artifacts to a release folder)
- PowerShell — Execute PowerShell scripts (e.g., calling BcContainerHelper to create containers)
The Test Runner App
Erik briefly shows the test runner app that ALBuild deploys before running tests. It’s remarkably simple — a single codeunit exposed as a web service. It has a RunCodeunit function where you specify a codeunit number, it runs that test codeunit, and returns any errors. Exposing a test runner as a web service makes it easy for ALBuild to trigger tests via HTTP calls without needing complex test infrastructure.
SaaS Deployment Under the Hood
Erik also peeks at the C# source code behind the SaaS deployment task. The cloud dev endpoint sits at /dev/apps, and deployment is simply a matter of posting the .app file as multipart form data to that endpoint (after obtaining an authentication token via service-to-service auth). The entire deploy task is less than 60 lines of C#. Most of the other tasks are similarly straightforward — the complexity is in orchestrating them, not in the individual steps.
Summary
ALBuild is Erik’s personal CI/CD tool for Business Central AL development — a C# command-line application driven by a JSON configuration file. It handles the complete build pipeline: version management, compilation, translation, code signing, deployment (to both Docker and SaaS), testing, artifact management, and Git operations. The entire process runs locally and completes in seconds rather than minutes. While there are other tools available in the ecosystem (like AL-OPS), ALBuild demonstrates that the underlying operations are surprisingly simple, and having full control over your build pipeline can be both practical and efficient — especially for solo developers or small teams.