How the ASP.NET Core eng Directory Powers the Development Workflow

The eng directory serves as the centralized build infrastructure backbone for ASP.NET Core, housing shell scripts, MSBuild targets, and shared properties that standardize building, testing, packaging, and publishing across all platforms and CI systems.

The dotnet/aspnetcore repository relies on this dedicated folder to maintain consistency across its massive, multi-platform codebase. By encapsulating version management, dependency resolution, and test orchestration in one location, the eng directory ensures that local developer workflows and automated Azure DevOps pipelines execute identical build logic. Any modification to the build process made within eng automatically propagates to all consuming projects throughout the repository.

Build Orchestration and Entry Points

The eng/build.sh script functions as the primary entry point for developers and CI agents. Located at the root of the eng folder, this Bash script parses CLI arguments—such as --configuration, --arch, --os-name, --build-managed, and --build-nodejs (lines 58‑78)—and constructs a unified msbuild_args array that feeds into the MSBuild engine (lines 115‑156).

When invoked, build.sh performs several critical initialization steps:

  1. Sets sensible defaults, such as building managed projects when no specific group is specified (lines 88‑96).
  2. Applies CI-specific tweaks, including binary logging and ulimit adjustments when the --ci flag is present (lines 71‑78).
  3. Bootstraps the Microsoft Arcade toolset by importing eng/common/tools.sh (line 81), which resolves the correct .NET SDK, restores necessary tools, and prepares the MSBuild environment.

The build.ps1 and build.cmd scripts are thin wrappers around this same logic, guaranteeing identical behavior across Windows PowerShell, Windows Command Prompt, and Unix-based shells.

Centralized Version and Dependency Management

Two property files within the eng directory act as the single source of truth for all versioning concerns.

eng/Versions.props defines core ASP.NET Core version components (AspNetCoreMajorVersion, AspNetCoreMinorVersion), pre-release labeling (PreReleaseVersionLabel, PreReleaseVersionIteration), and property-based version pins for third-party packages. For example, line 57 specifies <GoogleProtobufVersion>3.27.0</GoogleProtobufVersion>. Every project file imports this props file, ensuring version consistency eliminates drift across the codebase.

eng/Dependencies.props catalogs every external NuGet package as a <LatestPackageReference> item. A subsequent ItemGroup resolves each entry to concrete versions using the properties defined in Versions.props (lines 65‑78). This centralization enables source-only builds to pull packages from the dotnet-public feed and supplies runtime-specific RID packages for Crossgen2 and native runtimes (lines 107‑129).

Modular MSBuild Targets

The eng/targets/ directory contains modular .targets files that extend MSBuild functionality for specific scenarios:

  • Wix packaging for installer generation.
  • Helix test execution for distributed testing.
  • Functional-test asset management for end-to-end validation.
  • Multi-language support for C#, F#, C++, and NodeJS builds.

These files are imported by individual project files, allowing the build system to compose complex pipelines from discrete, maintainable components rather than embedding logic directly in .csproj files.

CI/CD Integration and Helix Test Orchestration

The eng/helix/helix.proj file configures Azure’s distributed test runner, Helix. This project defines targets that prepare the test environment (installing Node.js, JDK, and Chrome), upload test binaries and logs to Helix queues, and report results back to Azure DevOps. Functional-test projects reference these targets, enabling a single command—dotnet build /bl—to trigger end-to-end test execution on Microsoft-hosted infrastructure.

Supporting scripts in eng/scripts/ automate environment setup and validation:

  • install-nginx.sh and InstallGoogleChrome.ps1 spin up required external tools on CI agents.
  • update-selenium-and-playwright-versions.ps1 synchronizes browser automation versions with Versions.props.
  • CodeCheck.ps1 validates that Dependencies.props and the DependabotDiscovery project remain in sync.

Automation-Friendly Tooling

The eng/tools/DependabotDiscovery/ directory contains a "fake" project (DependabotDiscovery.csproj) designed specifically for dependency management automation. By mirroring external packages as <PackageReference> entries, this project allows Dependabot to discover and bump versions automatically. The README.md in this directory explains how the tool integrates with the central dependency catalog, ensuring automated updates flow back into eng/Versions.props correctly.

Additional property files like eng/TrimmableProjects.props and eng/Signing.props provide fine-grained controls for assembly trimming and code-signing artifacts during the publishing phase.

Practical Usage Examples

The following commands demonstrate how the eng directory facilitates common development tasks:


# Build default (managed) projects in Debug on current OS/arch

./eng/build.sh

# Build only NodeJS assets, skipping managed compilation

./eng/build.sh --no-build-managed --build-nodejs

# Perform a CI-ready Release build with binary logging

./eng/build.sh --ci --configuration Release

# Build a specific project without its dependencies

./eng/build.sh --no-build-deps --projects src/Mvc/Mvc.csproj

# Run Helix tests for a functional test project

dotnet test src/Testing/FunctionalTests/FunctionalTests.csproj /p:RunHelixTests=true

All options parse through eng/build.sh and resolve via the Arcade toolset, ensuring consistent behavior across Windows, macOS, and Linux.

Summary

  • The eng directory centralizes all build, test, and packaging logic for the ASP.NET Core repository, acting as the single integration point for Microsoft Arcade.
  • eng/build.sh serves as the universal entry point, parsing arguments and bootstrapping the toolset via eng/common/tools.sh.
  • eng/Versions.props and eng/Dependencies.props eliminate version drift by providing a unified catalog of package versions and runtime dependencies.
  • Modular MSBuild targets in eng/targets/ handle specialized tasks like Wix packaging and Helix test execution without polluting individual project files.
  • Automation scripts in eng/scripts/ and the DependabotDiscovery tooling ensure CI environments remain reproducible and dependencies stay current.

Frequently Asked Questions

What is the primary purpose of the eng directory in ASP.NET Core?

The eng directory houses the repository's build infrastructure, including shell scripts, MSBuild properties, and automation tools. It standardizes how developers and CI systems compile code, run tests, and produce packages by centralizing shared logic that would otherwise be duplicated across hundreds of project files.

How does eng/build.sh differ from build.cmd or build.ps1?

eng/build.sh is the canonical Bash implementation that contains the full argument parsing logic and MSBuild invocation sequence. build.cmd and build.ps1 are thin wrappers that delegate to this script (or its PowerShell equivalent), ensuring that Windows and Unix developers invoke identical build semantics regardless of shell environment.

What role does Microsoft Arcade play in the eng directory?

Microsoft Arcade is the shared build infrastructure used across .NET repositories. The eng directory imports Arcade via eng/common/tools.sh, which handles SDK resolution, tool restoration, and environment preparation. This integration allows ASP.NET Core to inherit centralized build improvements and maintain consistency with other dotnet repositories.

How does the eng directory handle automated dependency updates?

The eng/tools/DependabotDiscovery project creates a synthetic CSPROJ file containing <PackageReference> entries for all external dependencies. This allows Dependabot to detect outdated packages and propose version bumps. The eng/scripts/CodeCheck.ps1 script validates that these references remain synchronized with eng/Dependencies.props during CI runs, preventing configuration drift.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →