Problem: You run dotnet ef migrations add or dotnet ef database update and it fails — not because of a migration issue, but because of a Roslyn analyzer error in your project. The build log shows analyzer warnings treated as errors (CA2100, CS8600, or similar), and the EF command aborts before it even finds your DbContext.
Solution: Pass RunAnalyzersDuringBuild=false to the underlying MSBuild invocation using the -- separator:
# The fix — pass MSBuild property through the -- separator
dotnet ef migrations add MyMigration -- /p:RunAnalyzersDuringBuild=false
dotnet ef database update -- /p:RunAnalyzersDuringBuild=false
This disables Roslyn analyzer execution only for the EF tool’s internal build — not for your main application build. Your security-gated CI pipeline stays intact.
This post explains exactly why dotnet ef triggers your analyzers, every command variant that works, and how to structure your CI/CD pipeline so analyzers run on your application code but not on the EF design-time build.
Why dotnet ef Triggers Roslyn Analyzers
When you run any dotnet ef command, the EF Core CLI builds your project internally. It does this to discover your DbContext class, entity types, and migration history. This internal build invokes the full MSBuild pipeline — including your Roslyn analyzers.
If your project has:
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>in your.csproj/warnaserrorin your build arguments- Specific analyzer warnings promoted to errors with
<WarningsAsErrors>CA2100;CS8600</WarningsAsErrors>
…then an analyzer warning during the EF internal build becomes a build error, and dotnet ef aborts the command.
This is particularly common when:
- You’ve added a SAST analyzer NuGet package (
SecurityCodeScan.VS2019,SonarAnalyzer.CSharp, or a third-party analyzer) - Your project targets .NET 8 with
AnalysisLevel=latest-recommendedwhich enables many new rules - You’ve recently upgraded analyzer packages and new rules now fire on your codebase
- Your generated code (EF migration files themselves, scaffolded controllers) triggers analyzer warnings that you haven’t suppressed
The EF CLI analyzes the same code your application build analyzes — it just doesn’t need the security analysis to find a DbContext. That’s the core mismatch you’re resolving.
The Fix: Every Command Variant
The -- separator tells dotnet ef to pass all following arguments directly to MSBuild. Both /p: (Windows-style) and -p: (Unix/GNU-style) MSBuild property syntax work identically on all platforms.
dotnet ef migrations add
# Windows-style (works on Windows, Linux, macOS)
dotnet ef migrations add MyMigration -- /p:RunAnalyzersDuringBuild=false
# Unix-style short form (works on Windows, Linux, macOS)
dotnet ef migrations add MyMigration -- -p:RunAnalyzersDuringBuild=false
# With explicit project and startup project paths
dotnet ef migrations add MyMigration \
--project src/DataAccess \
--startup-project src/Api \
-- /p:RunAnalyzersDuringBuild=false
# PowerShell — quote if the shell strips the slash
dotnet ef migrations add MyMigration -- "/p:RunAnalyzersDuringBuild=false"
dotnet ef database update
# Apply all pending migrations
dotnet ef database update -- /p:RunAnalyzersDuringBuild=false
# Apply migrations up to a specific migration name
dotnet ef database update TargetMigration -- /p:RunAnalyzersDuringBuild=false
# With project paths
dotnet ef database update \
--project src/DataAccess \
--startup-project src/Api \
-- /p:RunAnalyzersDuringBuild=false
Also disabling code style enforcement
If your project also has <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>, you may need to disable that separately:
dotnet ef database update \
-- /p:RunAnalyzersDuringBuild=false /p:EnforceCodeStyleInBuild=false
Why -- Is Required
Without the -- separator, the EF CLI interprets /p:RunAnalyzersDuringBuild=false as an unknown dotnet ef argument and fails with an error like:
Unrecognized option '/p:RunAnalyzersDuringBuild=false'
The -- is an argument-separator convention: everything before -- belongs to dotnet ef; everything after -- is forwarded to the underlying MSBuild invocation. This is a standard EF Core CLI feature available in EF Core 5.0+ tooling.
If you see Error: unknown option '--', your dotnet-ef tool is out of date:
dotnet tool update --global dotnet-ef
Alternative: Configure the .csproj for Design-Time Builds
Instead of passing the flag on every command, conditionally disable analyzers in your .csproj for design-time builds:
<!-- .csproj — disable analyzers only during EF design-time builds -->
<PropertyGroup Condition="'$(DesignTimeBuild)' == 'true'">
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
</PropertyGroup>
This disables Roslyn analyzer execution when Visual Studio tooling or dotnet ef triggers a design-time build, but leaves analyzers enabled for your regular dotnet build and CI pipeline builds.
A more targeted approach — only disable analyzers when a custom property is passed:
<!-- .csproj -->
<PropertyGroup Condition="'$(SkipAnalyzersForEF)' == 'true'">
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
</PropertyGroup>
Then in your migration scripts:
dotnet ef database update -- /p:SkipAnalyzersForEF=true
And in your CI application build, SkipAnalyzersForEF is never set — analyzers run normally.
What NOT To Do
Do Not Set RunAnalyzersDuringBuild=false Globally
This is the most common mistake:
<!-- ⚠️ DO NOT DO THIS — disables ALL Roslyn analyzer runs globally -->
<PropertyGroup>
<RunAnalyzersDuringBuild>false</RunAnalyzersDuringBuild>
</PropertyGroup>
Setting this unconditionally disables analyzers on every build — including your CI security scan build. If you’re using Roslyn security rules (CA2100 for SQL injection, CA3001–CA3012 for various injection types, CA5350/CA5351 for weak cryptography), this configuration silently removes all of those checks from your pipeline.
The CI build log will show success with no analyzer warnings — because analyzers aren’t running. This is a false sense of security, not a solution.
Do Not Disable Analyzers in Your Main Build Step
# ⚠️ WRONG — disables security analysis on your application code
- name: Build
run: dotnet build -- /p:RunAnalyzersDuringBuild=false
The /p:RunAnalyzersDuringBuild=false flag belongs only on dotnet ef commands — never on your main application build.
The Correct CI/CD Pattern
Here’s the pipeline structure that keeps security analysis on your application build while avoiding analyzer conflicts on EF migration commands:
GitHub Actions
name: Build, Analyze & Migrate
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build-and-analyze:
name: Build + Security Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
- name: Restore
run: dotnet restore
# Analyzers run here — this is your security gate
- name: Build with Roslyn Analyzers
run: |
dotnet build --configuration Release \
/p:RunAnalyzersDuringBuild=true \
/p:AnalysisLevel=latest-recommended \
/warnaserror:CA2100,CA3001,CA3006,CA5350,CA5351
migrate:
name: Apply EF Migrations
runs-on: ubuntu-latest
needs: build-and-analyze
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.x'
- name: Install EF Tools
run: dotnet tool install --global dotnet-ef
# Analyzers disabled ONLY for the EF migration build
- name: Apply Migrations
run: |
dotnet ef database update \
--project src/DataAccess \
--startup-project src/Api \
-- /p:RunAnalyzersDuringBuild=false
env:
ConnectionStrings__Default: ${{ secrets.PROD_DB_CONNECTION }}
Key points:
- The
build-and-analyzejob runs with analyzers fully enabled — this is your security gate - The
migratejob only runs after a successful security-analyzed build (needs: build-and-analyze) - Analyzers are suppressed only in the EF migration step, not in the application build
- Migrations only run on the
mainbranch after the build passes
Azure DevOps
# azure-pipelines.yml
trigger:
- main
- develop
stages:
- stage: Build
jobs:
- job: BuildAndAnalyze
pool:
vmImage: 'ubuntu-latest'
steps:
- task: UseDotNet@2
inputs:
version: '8.x'
- script: dotnet restore
displayName: Restore
# Security-gated build with Roslyn analyzers
- script: |
dotnet build --configuration Release \
/p:RunAnalyzersDuringBuild=true \
/warnaserror:CA2100,CA3001,CA3006,CA5350,CA5351
displayName: Build + Security Analysis
- stage: Migrate
dependsOn: Build
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- job: ApplyMigrations
pool:
vmImage: 'ubuntu-latest'
steps:
- script: dotnet tool install --global dotnet-ef
displayName: Install EF Tools
# EF migration build — analyzers disabled
- script: |
dotnet ef database update \
--project src/DataAccess \
--startup-project src/Api \
-- /p:RunAnalyzersDuringBuild=false
displayName: Apply EF Migrations
env:
ConnectionStrings__Default: $(ProdDbConnection)
Roslyn Security Rules That Commonly Block dotnet ef
When dotnet ef fails due to analyzer errors, these are the most common culprits — and what they detect:
| Rule | What It Flags | Why EF Code Triggers It |
|---|---|---|
CA2100 | SQL injection in SqlCommand | Raw SQL in migration helper methods |
CA3001–CA3012 | Various injection patterns | Generated scaffolding code with raw queries |
CA5369 | Insecure XmlSerializer | Auto-generated serialization code |
CA5394 | Non-cryptographic random usage | Migration seed data using Random |
CS8600–CS8629 | Nullable reference warnings | Generated migration code in older projects |
IDE0xxx | Code style rules | Generated migration class formatting |
For CS warnings and IDE rules, the issue is usually that your migration files (which are auto-generated by dotnet ef) don’t conform to your project’s code style rules. In this case, suppressing analyzers for the EF build with -- /p:RunAnalyzersDuringBuild=false is the correct approach — not modifying the generated migration files to satisfy style rules.
Keeping Security Analysis Intact
Passing RunAnalyzersDuringBuild=false to dotnet ef commands is safe because:
- EF migration files themselves are not attack surfaces for injection vulnerabilities — they’re generated code that runs during deployment, not user-facing code that processes untrusted input
- Your application’s business logic, controller code, and data access layer are analyzed in your main build step, not the EF tool build
- The flag is applied surgically — only to the
dotnet efcommand, not todotnet build
However, Roslyn analyzers have a fundamental limitation: they perform only intra-method analysis. An analyzer can detect SQL injection when a SqlCommand is built with string concatenation in the same method as the Request.QueryString read — but it cannot trace injection chains that span multiple methods, service layers, or class boundaries.
For deeper security coverage of your .NET codebase — including interprocedural taint analysis, second-order SQL injection detection, and stored XSS across request boundaries — a dedicated SAST platform is required alongside Roslyn analyzers. Offensive360 runs as a separate analysis step in your CI/CD pipeline and does not interact with RunAnalyzersDuringBuild at all.
Quick Reference
| Task | Command |
|---|---|
migrations add (any platform) | dotnet ef migrations add Name -- /p:RunAnalyzersDuringBuild=false |
migrations add (Unix-style flag) | dotnet ef migrations add Name -- -p:RunAnalyzersDuringBuild=false |
database update | dotnet ef database update -- /p:RunAnalyzersDuringBuild=false |
database update + style rules | dotnet ef database update -- /p:RunAnalyzersDuringBuild=false /p:EnforceCodeStyleInBuild=false |
| Disable only for design-time | Add <Condition="'$(DesignTimeBuild)'=='true'"> to .csproj |
| Main app build (keep analyzers ON) | dotnet build /p:RunAnalyzersDuringBuild=true |
For the complete guide including all troubleshooting scenarios, Docker configuration, and the full CI/CD pipeline pattern, see: dotnet ef RunAnalyzersDuringBuild=false — Complete Guide.
Frequently Asked Questions
Does dotnet ef migrations add -- /p:RunAnalyzersDuringBuild=false work on Linux and macOS?
Yes. Both /p: and -p: property prefix styles work on Linux, macOS, and Windows in all modern .NET versions. The -- separator is available in EF Core 5.0+ tooling. If -- is not recognized, update: dotnet tool update --global dotnet-ef.
Will disabling analyzers for the EF build affect my migration files?
No. RunAnalyzersDuringBuild=false only affects the Roslyn analyzer execution during the EF tool’s internal project build. Your migration files are still generated with the same content. The flag has no effect on what migrations are created, how they’re structured, or how they’re applied to the database.
Why does dotnet ef succeed locally but fail in CI?
CI pipelines often have stricter build settings than local development. Common causes:
- CI sets
/warnaserrororTreatWarningsAsErrors=trueglobally — which your local build doesn’t have - CI uses a different .NET SDK version with additional analyzer rules enabled by default
- CI restores different NuGet package versions including newer analyzer packages with new rules
Adding -- /p:RunAnalyzersDuringBuild=false to your CI EF migration steps resolves all of these.
Is RunAnalyzersDuringBuild the same as RunCodeAnalysis?
They control different things. RunAnalyzersDuringBuild controls whether Roslyn source analyzers (NuGet analyzer packages and built-in SDK analyzers) run during the build. RunCodeAnalysis controls the older FxCop-style static analysis. In modern .NET projects, RunAnalyzersDuringBuild=false is the relevant flag. If your project still uses legacy FxCop rules, you may need to set both.
What if the EF command still fails after adding the flag?
Check whether your project has <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild> — this runs code style analysis (Roslyn analyzers for IDE0xxx rules) separately from RunAnalyzersDuringBuild. Pass both flags:
dotnet ef database update \
-- /p:RunAnalyzersDuringBuild=false /p:EnforceCodeStyleInBuild=false
Also verify you’re using dotnet-ef 5.0 or later: dotnet ef --version.
For deep security analysis of your .NET codebase that goes beyond Roslyn analyzers — detecting second-order SQL injection, stored XSS, and complex taint flows — Offensive360 SAST integrates with your Azure DevOps, GitHub Actions, or Jenkins pipeline without interfering with your EF migration workflow. Run a one-time scan for $500 or book a demo.