How do you implement CI/CD for Angular + ASP.NET Core?
For an Angular + ASP.NET Core Web API application, CI/CD automates the process of:
Developer pushes code
↓
Build Angular
↓
Build ASP.NET Core
↓
Run tests
↓
Create deployment artifacts
↓
Deploy automatically
↓
Azure / IIS / other hosting
A common implementation uses GitHub Actions or Azure DevOps Pipelines.
1. What is CI/CD?
CI/CD stands for:
- CI — Continuous Integration
- CD — Continuous Delivery / Continuous Deployment
Continuous Integration
Whenever developers push code:
Git Push
↓
Restore dependencies
↓
Build
↓
Run tests
↓
Validate application
The goal is to detect integration/build/test problems early.
Continuous Deployment
After CI succeeds:
Build successful
↓
Create artifact
↓
Deploy
↓
SIT / UAT / Production
Depending on the organization's process, production deployment may be automatic or require approval.
2. Example architecture
Suppose your application uses:
Angular
↓
Azure Static Web Apps
ASP.NET Core Web API
↓
Azure App Service
Database
↓
Azure SQL
The repository could be:
Portfolio/
│
├── frontend/
│ ├── src/
│ ├── package.json
│ └── angular.json
│
├── backend/
│ ├── Portfolio.Api/
│ ├── Portfolio.Application/
│ ├── Portfolio.Infrastructure/
│ └── Portfolio.sln
│
└── .github/
└── workflows/
CI/CD:
GitHub
|
├── frontend changed
│ ↓
│ Build Angular
│ ↓
│ Deploy Static Web App
│
└── backend changed
↓
Build .NET
↓
Test
↓
Publish
↓
Deploy App Service
3. Angular CI process
Angular normally requires:
Node.js
npm
Angular dependencies
Typical pipeline commands:
npm ci
npm run build -- --configuration production
If tests are configured:
npm test
The build produces something similar to:
dist/
└── my-app/
└── browser/
├── index.html
├── main-XXXX.js
├── styles-XXXX.css
└── chunk-XXXX.js
That becomes the frontend deployment artifact.
4. Why use npm ci instead of npm install?
In CI pipelines, you'll commonly see:
npm ci
instead of:
npm install
npm ci uses the lock file to perform a clean, reproducible dependency installation.
Typically:
package.json
+
package-lock.json
↓
npm ci
↓
Dependencies installed
↓
Angular build
This makes it well suited to automated build servers.
5. ASP.NET Core CI process
The backend typically uses:
dotnet restore
then:
dotnet build --configuration Release
then:
dotnet test --configuration Release
and finally:
dotnet publish --configuration Release --output ./publish
Flow:
ASP.NET Core source
↓
dotnet restore
↓
dotnet build
↓
dotnet test
↓
dotnet publish
↓
publish/
The publish directory becomes the deployable backend artifact.
6. Full GitHub Actions Example
Let's implement a simple pipeline using GitHub Actions.
Create:
.github/
└── workflows/
└── ci-cd.yml
ci-cd.yml
name: Angular + ASP.NET Core CI/CD
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build-angular:
runs-on: ubuntu-latest
defaults:
run:
working-directory: frontend
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Install dependencies
run: npm ci
- name: Build Angular
run: npm run build -- --configuration production
- name: Upload Angular artifact
uses: actions/upload-artifact@v4
with:
name: angular-app
path: frontend/dist/
build-api:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- name: Restore
run: dotnet restore backend/Portfolio.sln
- name: Build
run: >
dotnet build
backend/Portfolio.sln
--configuration Release
--no-restore
- name: Test
run: >
dotnet test
backend/Portfolio.sln
--configuration Release
--no-build
- name: Publish API
run: >
dotnet publish
backend/Portfolio.Api/Portfolio.Api.csproj
--configuration Release
--output ./api-publish
- name: Upload API artifact
uses: actions/upload-artifact@v4
with:
name: api
path: ./api-publish
This is the CI/build portion.
7. What happens when code is pushed?
Suppose you run:
git add .
git commit -m "Add products feature"
git push
GitHub sees:
on:
push:
branches:
- main
and starts the workflow.
Developer
↓
git push
↓
GitHub main branch
↓
GitHub Actions
|
├───────────────┐
↓ ↓
Angular CI ASP.NET CI
↓ ↓
npm ci dotnet restore
↓ ↓
Build Build
↓ ↓
Test Test
↓ ↓
Artifact Publish
↓
Artifact
8. What is a pipeline artifact?
An artifact is the output produced by the build pipeline that can later be deployed.
For Angular:
angular-app artifact
↓
dist/
For ASP.NET Core:
api artifact
↓
publish/
This separation is useful because:
Build
↓
Artifact
↓
Deploy SIT
↓
Deploy UAT
↓
Deploy Production
Ideally, especially in enterprise pipelines, the same tested artifact progresses through environments rather than recompiling source code differently at every deployment stage.
9. Add ASP.NET Core deployment to Azure App Service
After building the API, you can add a deployment job.
Conceptually:
deploy-api:
needs: build-api
runs-on: ubuntu-latest
steps:
- name: Download API artifact
uses: actions/download-artifact@v4
with:
name: api
path: api-publish
- name: Deploy API
uses: azure/webapps-deploy@v3
with:
app-name: my-portfolio-api
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
package: api-publish
Now:
Build API
↓
Upload artifact
↓
deploy-api
↓
Download artifact
↓
Azure App Service
10. Where should Azure credentials be stored?
Never put deployment credentials directly into the YAML.
Wrong:
password: MyAzurePassword123
Instead, use the CI/CD platform's protected secrets or, preferably where supported, workload/federated identity.
For a GitHub secret example:
GitHub Repository
↓
Settings
↓
Secrets and variables
↓
Actions
Then your workflow can reference:
${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
The principle is:
Pipeline file
↓
References secret
↓
GitHub protected secret / identity
↓
Azure authentication
11. Angular deployment
If Angular is separately hosted, you can deploy it to a static hosting service such as Azure Static Web Apps.
Architecture:
GitHub
↓
Angular Pipeline
↓
npm ci
↓
Production build
↓
dist/
↓
Azure Static Web Apps
The backend can independently follow:
GitHub
↓
.NET Pipeline
↓
dotnet publish
↓
Azure App Service
So you get:
GitHub
|
┌────────┴────────┐
↓ ↓
Angular ASP.NET Core
↓ ↓
Static Web Apps App Service
| |
└──── HTTPS ─────→|
↓
Azure SQL
12. Environment configuration
Suppose you have:
Development
SIT
UAT
Production
API URLs might be:
SIT
https://sit-api.example.com/api
UAT
https://uat-api.example.com/api
Production
https://api.example.com/api
With Angular build-time configuration, you might have:
environment.sit.ts
environment.uat.ts
environment.production.ts
and build using:
ng build --configuration sit
or:
ng build --configuration uat
or:
ng build --configuration production
However, this produces different Angular artifacts.
13. Build once, deploy many
Enterprise CI/CD often prefers:
Build once
↓
Artifact
├──→ SIT
├──→ UAT
└──→ Production
rather than:
Build for SIT
Build again for UAT
Build again for Production
Why?
Because rebuilding can technically create different artifacts.
A stronger deployment model is:
Source
↓
CI
↓
Build + Test
↓
Versioned Artifact
↓
SIT
↓
Testing
↓
UAT
↓
Approval
↓
Production
For Angular, this often means using runtime public configuration rather than compiling environment-specific URLs into every build.
For example:
{
"apiUrl": "https://api.example.com/api"
}
The environment supplies the appropriate public configuration.
14. ASP.NET Core environment configuration
ASP.NET Core is particularly suited to environment-specific runtime configuration.
You might have:
appsettings.json
appsettings.SIT.json
appsettings.UAT.json
appsettings.Production.json
But production secrets should normally come from secure external configuration such as:
Azure App Service Configuration
Environment Variables
Azure Key Vault
For example:
ASP.NET Core
↓
IConfiguration
↓
App Service configuration
↓
Key Vault
↓
Connection String / Secrets
This allows the same published API artifact to run in multiple environments with different runtime settings.
15. SIT → UAT → Production pipeline
A real-world flow could be:
Developer
↓
Feature Branch
↓
Pull Request
↓
CI
├── Angular Build
├── Angular Tests
├── .NET Build
└── .NET Tests
↓
Code Review
↓
Merge main
↓
Create artifacts
↓
Deploy SIT
↓
Automated / Integration Tests
↓
Deploy UAT
↓
UAT Testing
↓
Approval
↓
Deploy Production
This is much closer to the way CI/CD is discussed in senior/lead-level interviews.
16. Production approval
You don't necessarily want every commit to immediately deploy to production.
For example:
main
↓
Build
↓
SIT
↓
UAT
↓
Manual Approval
↓
Production
GitHub Environments or Azure DevOps environments can be used to implement deployment controls and approvals.
17. Database deployment
The database requires special attention.
Avoid treating a production database exactly like replaceable application files.
A common architecture is:
Application Artifact
↓
Deployment Pipeline
|
├── Deploy Angular
├── Deploy API
└── Apply controlled DB migration
For EF Core, migrations might be generated/deployed through a controlled process.
Production database migrations should consider:
- backups/recovery
- backward compatibility
- deployment ordering
- long-running migrations
- locking/downtime
- rollback strategy
For important production systems, blindly running database changes on every application startup is often undesirable.
18. CI vs CD responsibilities
| CI | CD |
|---|---|
| Checkout code | Download/use artifact |
| Restore dependencies | Deploy SIT |
| Compile Angular | Deploy UAT |
| Compile .NET | Deploy Production |
| Run unit tests | Environment configuration |
| Static analysis | Smoke tests |
| Create artifacts | Approvals |
| Validate code | Release/rollback |
Think:
CI
"Can I safely produce a deployable artifact?"
CD
"How do I release that artifact?"
19. What happens if tests fail?
Suppose:
git push
↓
CI starts
↓
Build
↓
Tests
↓
FAIL
Then deployment should not continue.
Test failed
↓
Pipeline failed
↓
No deployment
This is one of the major benefits of CI/CD.
20. Rollback
Production pipelines should also consider rollback.
For example:
Version 1.5
↓
Deploy
↓
Problem detected
↓
Rollback
↓
Version 1.4
This is easier when you keep versioned immutable artifacts.
For example:
portfolio-ui-1.4
portfolio-ui-1.5
portfolio-api-1.4
portfolio-api-1.5
Then you're not rebuilding old source code during an emergency rollback.
21. Branch strategy example
A simple approach:
feature/product-search
↓
Pull Request
↓
main
↓
CI
↓
Build/Test
↓
Artifact
↓
SIT
↓
UAT
↓
Production
The exact branch model varies by organization. CI/CD does not require a particular branching strategy.
22. Separate frontend/backend pipelines
For a larger application, I would usually avoid one huge pipeline that redeploys everything for every small change.
For example:
angular-ci-cd.yml
api-ci-cd.yml
Angular changes:
frontend/**
↓
Angular pipeline
Backend changes:
backend/**
↓
API pipeline
This can reduce unnecessary builds and deployments.
23. Combined deployment alternative
If Angular is hosted from ASP.NET Core's wwwroot, the pipeline changes.
Angular source
↓
ng build
↓
dist/.../browser
↓
Copy into API/wwwroot
↓
dotnet publish
↓
Single artifact
↓
Azure App Service
For example:
wwwroot/
├── index.html
├── main-XXXX.js
├── styles-XXXX.css
└── chunk-XXXX.js
Then ASP.NET Core:
app.UseDefaultFiles();
app.UseStaticFiles();
app.MapControllers();
app.MapFallbackToFile("index.html");
Now there is only one deployable application artifact.
Separate vs Combined CI/CD
| Separate | Combined |
|---|---|
| Angular artifact | One combined artifact |
| API artifact | Angular inside wwwroot |
| Independent deployment | Single deployment |
| Independent scaling | Coupled scaling |
| More pipeline components | Simpler release topology |
| Good for larger separated architectures | Convenient for simpler applications |
Recommended Pipeline Structure
For a separately deployed Angular + ASP.NET Core application:
GitHub
|
↓
Pull Request
|
↓
CI Pipeline
|
┌──────────┴──────────┐
↓ ↓
Angular .NET API
↓ ↓
npm ci dotnet restore
↓ ↓
tests tests
↓ ↓
build build
↓ ↓
UI Artifact API Artifact
│ │
└──────────┬──────────┘
↓
CD Pipeline
↓
SIT
↓
Tests
↓
UAT
↓
Approval
↓
Production
Key Points
- CI builds, tests, and validates Angular and ASP.NET Core.
- CD deploys the resulting artifacts.
- Angular typically uses:
npm ci
npm run build -- --configuration production
- ASP.NET Core typically uses:
dotnet restore
dotnet build
dotnet test
dotnet publish
- Store deployable output as pipeline artifacts.
- Never hard-code deployment credentials in YAML.
- Use protected secrets or secure identity mechanisms.
- Keep environment-specific backend configuration outside the application artifact where practical.
- Build once, deploy many is a strong enterprise deployment model.
- SIT → UAT → Production can use the same versioned artifact.
- Production deployment can require approval.
- Database changes need a controlled migration strategy.
- Keep previous artifacts/releases available to support rollback.
- Angular and ASP.NET Core can have separate pipelines when independently deployed.
Interview Questions and Answers
1. What is CI/CD?
CI continuously integrates changes by automatically building and testing them. CD automates delivering or deploying the validated artifact to environments such as SIT, UAT, and Production.
2. How do you implement CI/CD for Angular + ASP.NET Core?
I configure a pipeline using GitHub Actions or Azure DevOps. The pipeline restores dependencies, builds and tests Angular and ASP.NET Core, publishes deployable artifacts, and then deploys those artifacts through the required environments.
3. What commands do you use for Angular CI?
Typically:
npm ci
npm run build -- --configuration production
along with the project's configured test command.
4. What commands do you use for ASP.NET Core?
Typically:
dotnet restore
dotnet build -c Release
dotnet test -c Release
dotnet publish -c Release
5. Why use npm ci in a pipeline?
It performs a clean dependency installation based on the lock file, making builds more reproducible for CI environments.
6. What is a pipeline artifact?
A pipeline artifact is the deployable output produced by CI, such as Angular's built static files or ASP.NET Core's dotnet publish output.
7. What does "build once, deploy many" mean?
The application is built and tested once, producing a versioned artifact. The same artifact is promoted through SIT, UAT, and Production while environment-specific configuration is supplied at deployment/runtime.
8. Where should production secrets be stored?
Not in Angular code, source control, or plain YAML. Backend secrets should be supplied through secure mechanisms such as Azure App Service configuration, protected pipeline secrets, environment variables, or Azure Key Vault.
9. What happens when unit tests fail?
The pipeline should fail and prevent the application from progressing to deployment.
10. How do you deploy Angular and ASP.NET Core separately?
A typical Azure setup is:
Angular
↓
Azure Static Web Apps
ASP.NET Core
↓
Azure App Service
Each can have an independent build/deployment pipeline.
11. How do you handle Production deployment?
Promote the tested artifact to the Production environment, optionally requiring manual approval, and run post-deployment validation/smoke tests.
12. How do you handle rollback?
Keep versioned deployment artifacts/releases so the previous known-good version can be redeployed without rebuilding source code.
Short interview answer
For Angular + ASP.NET Core CI/CD, I use a pipeline such as GitHub Actions or Azure DevOps. CI checks out the code, installs Angular dependencies with
npm ci, builds/tests Angular, restores/builds/tests the .NET solution, and creates versioned deployment artifacts. CD then promotes those artifacts through environments such as SIT, UAT, and Production, using environment-specific runtime configuration, protected secrets, approvals, smoke tests, and a rollback strategy.