ModularPipelines: CI/CD as C# Code, with Compile-Time Checks and Local Debugging
Write your pipelines in C# . | | ModularPipelines.Java | Helpers for interacting with Java build tools (Maven, Gradle).
At a glance
- What is it?
- ModularPipelines replaces YAML pipelines with C# modules that run locally and in CI. It brings IDE support, dependency injection, and Roslyn analyzers to pipeline development, but adopting it means committing to the .NET ecosystem.
- Who is it for?
- Adopt ModularPipelines if your team already lives in C# and wants to debug pipelines locally with breakpoints and compile-time safety. Do not use it if you prefer YAML's declarative simplicity or need to support non-.NET contributors, since the pipeline is now a C# codebase that requires .NET tooling and knowledge.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 14, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The YAML Debugging Loop It Removes
ModularPipelines targets a specific pain: the push-and-wait cycle of YAML-based CI. The README describes YAML pipelines as impossible to debug locally, lacking compile-time safety, and prone to copy-paste duplication. The project's answer is to express pipelines as C# classes that run as a normal .NET application. Instead of editing a declarative file and triggering a remote agent, you set a breakpoint in your IDE, step through the pipeline, and fix the logic before pushing. This is a fundamental shift: the pipeline is not a configuration artifact, it is executable program code with the same tooling as your application. For teams that already write C#, that removes a whole class of feedback-loop delays.
Modules, Dependencies, and Parallel Execution
The core abstraction is a module. A module inherits from Module<T> and overrides ExecuteAsync, returning a strongly-typed result. Dependencies are declared with attributes, as in [DependsOn<BuildModule>] on a PublishModule. The framework reads these attributes to build a dependency graph. According to the README, ModularPipelines figures out what can run in parallel and maximizes throughput, so you do not manually orchestrate parallel jobs. Modules share data by returning results that other modules consume; the README emphasizes no shared mutable state, just clean data flow. This design is similar to task graphs in build systems, but here the graph is defined in code and validated at compile time.
Compile-Time Checks and Roslyn Analyzers
One of the most distinctive features is the built-in Roslyn analyzers. The README lists specific mistakes they catch: missing [DependsOn] when calling GetModule<T>(), circular dependencies between modules, forgetting to await module results, and using Console.Write instead of the logging system. This moves pipeline correctness checks from runtime to compile time. That is a real advantage over YAML, where a typo in a variable name or a bad indentation only surfaces when the CI agent runs. The analyzers are a concrete mechanism, not a vague promise. However, the README does not describe how the analyzers are configured or whether they are enabled by default, so you would need to check the template or documentation to confirm the exact behavior.
Getting Started: Template and Package Installation
The quick start uses the dotnet CLI. You install the template with dotnet new install ModularPipelines.Templates, then scaffold a new pipeline with dotnet new modularpipeline -n MyPipeline --solution ../MySolution.slnx --publish-project ../src/MyApp/MyApp.csproj. The generated project contains separate restore, build, test, and publish modules with explicit dependencies and configurable paths. You then run it with dotnet run. For adding modules to an existing project, the README shows installing the core packages with dotnet add package ModularPipelines and dotnet add package ModularPipelines.DotNet, then configuring and running from Program.cs using Pipeline.CreateBuilder(args) and await builder.RunAsync(). This is straightforward for anyone familiar with .NET project setup.
Integrations: A Wide Net but Verify Coverage
The README lists a long table of integration packages: ModularPipelines.AmazonWebServices, Ansible, ArgoCd, Azure, Azure.Pipelines, Chocolatey, Cmd, Cosign, Docker, and more. These are described as helpers for interacting with each tool's CLI. This is a practical advantage: you get strongly-typed wrappers for common commands, so you do not need to shell out to raw CLI strings. But the list is not exhaustive, and the README is truncated, so you cannot confirm the maturity or completeness of each wrapper. If your pipeline uses a niche tool not on the list, you will need to fall back to generic process execution or write your own module. That is a limitation worth checking before committing.
Secrets, Logging, and Dependency Injection
Three features stand out in the README. First, secrets are automatically obfuscated in logs, which addresses a common CI failure where API keys leak into build output. Second, the framework supports full dependency injection, similar to ASP.NET Core, so you can inject services and configuration and mock dependencies for testing. Third, modules share data through strongly-typed results, avoiding shared mutable state. These are not just conveniences; they change how you structure pipeline logic. Instead of environment variable gymnastics, you use DI. Instead of parsing log output, you get typed results. That said, the README does not explain how secret obfuscation works under the hood, so you should verify that it covers your specific logging paths.
The Wrong Tool: When YAML Still Makes Sense
ModularPipelines is not a universal replacement. If your team includes non-.NET developers, or if your pipeline is simple enough that YAML is clear, the overhead of a C# codebase may not be worth it. The README's own pitch is about debugging and compile-time safety, which only matters if you are already comfortable with C# and .NET tooling. Also, the project is tied to the .NET ecosystem: the template, the packages, and the analyzers all assume a .NET environment. If your CI agent does not have the .NET SDK, you would need to add that. The README does not discuss cross-platform agent support in detail, but the packages for Cmd and Chocolatey suggest a Windows orientation, even though .NET itself is cross-platform. For teams that want a declarative pipeline with minimal code, this is the wrong tool.
Alternatives: YAML and Other Code-First Systems
The obvious alternative is staying with YAML in your current CI provider, whether GitHub Actions, Azure Pipelines, or TeamCity. The difference is the underlying model: YAML is declarative and provider-specific, while ModularPipelines is imperative and provider-agnostic. The README claims you can switch build systems by changing one line, because your modules stay the same. That is a genuine architectural difference. Another alternative is a code-first CI product like Buildkite's Pipelines as Code or Dagger, which also let you write pipelines in a general-purpose language. The difference is that Dagger uses a containerized engine and a separate SDK, while ModularPipelines is a plain .NET library that runs directly with dotnet run. If you are already in .NET, ModularPipelines is simpler to adopt; if you want a language-agnostic approach, Dagger might be more flexible.
Maintenance and License
The project is MIT-licensed, which means you can use and modify it freely, including in commercial products, with attribution. The repository is actively maintained, with recent releases in 2026 (v3.2.8 in April, v3.1.90 in February, v3.1.6 in January). That suggests a steady release cadence, but you should not infer maturity from release frequency alone. The maintenance cost for you comes from keeping up with new versions and from debugging your own pipeline code, which is now a normal C# application. The README does not mention a migration guide or upgrade process, so plan to read release notes manually. Also, because the pipeline is code, you need to apply the same version control and code review practices as your application code.
Editorial conclusion
Adopt ModularPipelines if your team already lives in C# and wants to debug pipelines locally with breakpoints and compile-time safety. Do not use it if you prefer YAML's declarative simplicity or need to support non-.NET contributors, since the pipeline is now a C# codebase that requires .NET tooling and knowledge. Before adopting, verify that the modules you need are covered by the available integration packages, and check the template output against your actual build steps, because the generated modules only cover restore, build, test, and publish with configurable paths.
Community notes