CI/CD para projetos .NET: como montar um pipeline eficiente

CI/CD para projetos .NET: como montar um pipeline eficiente
Publicado em 30/10/2026 por Admin

A qualidade de um projeto de software não depende apenas de escrever um bom código. Também é fundamental garantir que as alterações desenvolvidas sejam testadas, validadas e disponibilizadas de maneira segura e consistente.

Em equipes de desenvolvimento modernas, realizar manualmente todas essas etapas pode consumir muito tempo, aumentar a possibilidade de erros e dificultar a frequência das entregas.

É justamente nesse cenário que entram as práticas de CI/CD (Continuous Integration e Continuous Delivery/Deployment).

Com um pipeline bem estruturado, desenvolvedores conseguem automatizar tarefas como restauração de dependências, compilação, execução de testes automatizados, geração de artefatos e publicação de aplicações.

No ecossistema .NET, existem diversas ferramentas que permitem implementar esse processo, como GitHub Actions e Azure DevOps.

Neste artigo, vamos entender como funciona CI/CD, quais são as etapas de um pipeline eficiente e como implementar uma automação prática para projetos desenvolvidos em .NET.

O que é CI/CD?

CI/CD é um conjunto de práticas utilizadas para automatizar e melhorar o processo de integração, validação e entrega de software.

A sigla representa três conceitos importantes:

  • CI (Continuous Integration): integração contínua.

  • CD (Continuous Delivery): entrega contínua.

  • CD (Continuous Deployment): implantação contínua.

Embora estejam relacionados, cada conceito possui uma responsabilidade específica.

Continuous Integration (CI) – Integração Contínua

A integração contínua consiste em integrar frequentemente as alterações desenvolvidas por diferentes programadores em um repositório compartilhado.

Sempre que uma alteração é enviada para o repositório, um processo automatizado é executado para verificar se o código continua funcionando corretamente.

Em um projeto .NET, esse processo normalmente envolve:

  1. Recuperar o código-fonte do repositório.

  2. Configurar o SDK do .NET.

  3. Restaurar os pacotes NuGet.

  4. Compilar a aplicação.

  5. Executar os testes automatizados.

  6. Gerar relatórios de validação.

O principal objetivo é identificar problemas rapidamente, antes que eles cheguem a outros ambientes ou sejam incorporados à versão principal da aplicação.

Continuous Delivery (CD) – Entrega Contínua

A entrega contínua amplia o processo de integração.

Depois que o código passa pelas validações automatizadas, uma versão pronta para implantação é gerada e disponibilizada como artefato.

Esse artefato pode ser utilizado posteriormente para realizar o deploy em ambientes como:

  • Desenvolvimento (Development).

  • Homologação (Staging).

  • Produção (Production).

Na entrega contínua, a implantação em produção normalmente depende de uma aprovação ou autorização específica.

Continuous Deployment – Implantação Contínua

Na implantação contínua, o processo é ainda mais automatizado.

Depois que todas as validações são aprovadas, a aplicação pode ser publicada automaticamente em produção, sem a necessidade de uma aprovação manual para cada versão.

Essa abordagem exige um nível elevado de confiança nos testes automatizados, nos mecanismos de monitoramento e nos procedimentos de rollback.

Por que implementar CI/CD em projetos .NET?

Projetos desenvolvidos em .NET podem possuir diferentes níveis de complexidade.

Uma aplicação ASP.NET Core pode depender de APIs externas, bancos de dados, serviços de mensageria, bibliotecas NuGet e outros componentes.

À medida que o projeto cresce, validar manualmente todas essas dependências e funcionalidades se torna cada vez mais trabalhoso.

A implementação de CI/CD oferece algumas vantagens importantes.

1. Redução de erros durante as entregas

A compilação e os testes são executados automaticamente a cada alteração.

Isso permite identificar problemas antes que o código seja integrado à versão principal.

2. Padronização do processo de desenvolvimento

Todos os desenvolvedores utilizam o mesmo processo de validação.

Independentemente de quem realizou a alteração, as mesmas verificações são executadas pelo pipeline.

3. Maior velocidade nas entregas

Tarefas repetitivas deixam de depender de execução manual.

Com isso, a equipe pode dedicar mais tempo ao desenvolvimento de funcionalidades e à resolução de problemas.

4. Maior confiabilidade nas implantações

A geração de artefatos padronizados permite que o mesmo pacote validado seja utilizado nos diferentes ambientes.

Isso reduz diferenças entre aquilo que foi testado e aquilo que será disponibilizado aos usuários.

5. Facilidade para identificar problemas

Quando uma alteração provoca uma falha na compilação ou nos testes, o pipeline apresenta informações que ajudam a identificar a origem do problema.

Quais ferramentas utilizar para CI/CD em projetos .NET?

Existem diferentes ferramentas para implementar pipelines de integração e entrega contínua.

A escolha depende da infraestrutura, das tecnologias utilizadas e das necessidades da equipe.

As duas alternativas bastante utilizadas no ecossistema .NET são GitHub Actions e Azure DevOps.

GitHub Actions

O GitHub Actions permite criar fluxos de automação diretamente nos repositórios hospedados no GitHub.

Os pipelines são definidos por meio de arquivos YAML armazenados no diretório:

.github/workflows/

Entre suas principais características estão:

  • Integração direta com repositórios GitHub.

  • Execução automática a partir de eventos do repositório.

  • Suporte a diferentes sistemas operacionais.

  • Integração com testes e ferramentas de qualidade.

  • Publicação de artefatos.

  • Integração com serviços de cloud.

É uma excelente alternativa para projetos pessoais, aplicações corporativas e equipes que já utilizam GitHub para gerenciamento do código-fonte.

Documentação oficial: https://docs.github.com/en/actions

Azure DevOps

O Azure DevOps oferece um conjunto de ferramentas para gerenciamento do ciclo de vida de desenvolvimento de software.

Dentro desse ecossistema, o Azure Pipelines é responsável pela automação de processos de CI/CD.

Ele permite criar pipelines utilizando arquivos YAML ou interfaces visuais.

Entre suas funcionalidades estão:

  • Integração com repositórios Git.

  • Compilação e testes automatizados.

  • Publicação de artefatos.

  • Gerenciamento de ambientes.

  • Aprovações para implantação.

  • Integração com Azure App Service, Azure Functions e outros serviços.

Uma vantagem importante é a possibilidade de centralizar diferentes etapas do processo de desenvolvimento em uma única plataforma.

Documentação oficial: https://learn.microsoft.com/en-us/azure/devops/pipelines/

Qual ferramenta escolher?

As duas ferramentas conseguem atender muito bem projetos .NET.

Uma comparação simplificada:

Critério GitHub Actions Azure DevOps
Integração com GitHub Nativa Disponível
Configuração YAML Sim Sim
Build e testes .NET Sim Sim
Publicação de artefatos Sim Sim
Aprovação de ambientes Sim Sim
Integração com Azure Sim Sim
Gerenciamento de projetos Ecossistema GitHub Azure Boards
Execução em agentes próprios Sim Sim

Minha recomendação é utilizar GitHub Actions quando o repositório já está hospedado no GitHub e a equipe deseja uma automação simples e integrada.

Já o Azure DevOps pode ser especialmente interessante para organizações que utilizam Azure Boards, Azure Repos e outros recursos da plataforma.

Como estruturar um pipeline eficiente para projetos .NET?

Antes de começar a implementação, é importante definir quais etapas devem fazer parte do processo.

Um pipeline eficiente não precisa ser extremamente complexo. O mais importante é garantir que as validações necessárias sejam executadas na ordem correta.

Uma estrutura inicial pode ser dividida nas seguintes etapas:

Etapa 1 – Checkout do código-fonte

O primeiro passo é recuperar o código-fonte do repositório.

O pipeline precisa acessar a versão que será validada para executar as próximas etapas.

Etapa 2 – Configuração do ambiente .NET

É necessário disponibilizar a versão correta do SDK do .NET.

Isso evita problemas de compatibilidade entre o ambiente utilizado pelo desenvolvedor e o ambiente de execução do pipeline.

Uma boa prática é manter a versão do SDK documentada no arquivo global.json.

Etapa 3 – Restore das dependências

O comando dotnet restore realiza a restauração das dependências declaradas nos projetos.

Essa etapa garante que os pacotes NuGet necessários estejam disponíveis para a compilação.

Etapa 4 – Build da aplicação

Com as dependências restauradas, o próximo passo é compilar a solução.

O comando dotnet build identifica problemas de compilação e verifica se o código pode ser transformado em uma aplicação executável.

Etapa 5 – Execução dos testes automatizados

Depois da compilação, o pipeline deve executar os testes automatizados.

Em projetos .NET, podemos utilizar ferramentas como:

  • xUnit.

  • NUnit.

  • MSTest.

Os testes devem validar as principais regras de negócio, comportamentos esperados e integrações relevantes.

Etapa 6 – Análise de qualidade

Dependendo da maturidade do projeto, podemos adicionar verificações complementares:

  • Análise estática de código.

  • Verificação de vulnerabilidades em dependências.

  • Análise de cobertura de testes.

  • Verificação de padrões de codificação.

  • Análise de qualidade com SonarQube.

Essas verificações ajudam a identificar problemas que não necessariamente são encontrados durante a compilação.

Etapa 7 – Publicação da aplicação

Se todas as etapas anteriores forem concluídas com sucesso, podemos utilizar o comando dotnet publish.

Esse comando prepara os arquivos necessários para disponibilizar a aplicação em outro ambiente.

Etapa 8 – Deploy

A última etapa consiste em disponibilizar a aplicação no ambiente de destino.

Dependendo da infraestrutura, podemos realizar a publicação em:

  • Azure App Service.

  • Azure Functions.

  • Máquinas virtuais.

  • Containers Docker.

  • Kubernetes.

  • Servidores Windows com IIS.

Uma boa estratégia é separar o processo de build e validação do processo de implantação.

Dessa maneira, conseguimos utilizar o mesmo artefato em diferentes ambientes.

Implementando CI/CD com GitHub Actions em um projeto .NET

Agora vamos colocar os conceitos em prática.

Imagine que temos uma solução desenvolvida em ASP.NET Core, organizada da seguinte maneira:

MinhaAplicacao/
│
├── MinhaAplicacao.sln
│
├── MinhaAplicacao.Api/
│   ├── Controllers/
│   ├── Services/
│   └── MinhaAplicacao.Api.csproj
│
├── MinhaAplicacao.Domain/
│   └── MinhaAplicacao.Domain.csproj
│
└── MinhaAplicacao.Tests/
    └── MinhaAplicacao.Tests.csproj

Nosso objetivo é criar um pipeline que execute automaticamente:

  1. Recuperação do código.

  2. Configuração do SDK .NET.

  3. Restauração das dependências.

  4. Compilação da solução.

  5. Execução dos testes.

  6. Publicação da aplicação.

  7. Armazenamento do artefato gerado.

Para este exemplo, utilizaremos .NET 10, uma versão LTS disponível em outubro de 2026. Caso seu projeto utilize outra versão suportada, ajuste a configuração do SDK conforme necessário.

Criando o arquivo do pipeline

Dentro do repositório, crie a seguinte estrutura:

.github/
└── workflows/
    └── dotnet-ci.yml

O arquivo dotnet-ci.yml será responsável por definir as etapas de automação.

Vamos utilizar a seguinte implementação:

name: .NET CI Pipeline

on:
  push:
    branches:
      - main
      - develop

  pull_request:
    branches:
      - main
      - develop

jobs:
  build-and-test:

    runs-on: ubuntu-latest

    steps:

      - name: Checkout repository
        uses: actions/checkout@v6

      - name: Setup .NET
        uses: actions/setup-dotnet@v6
        with:
          dotnet-version: '10.0.x'

      - name: Restore dependencies
        run: dotnet restore MinhaAplicacao.sln

      - name: Build solution
        run: >
          dotnet build MinhaAplicacao.sln
          --configuration Release
          --no-restore

      - name: Run tests
        run: >
          dotnet test MinhaAplicacao.sln
          --configuration Release
          --no-build
          --logger "trx;LogFileName=test-results.trx"

      - name: Publish application
        run: >
          dotnet publish MinhaAplicacao.Api/MinhaAplicacao.Api.csproj
          --configuration Release
          --no-restore
          --output ./publish

      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
          name: minha-aplicacao
          path: ./publish
          retention-days: 7

Importante: os caminhos utilizados no exemplo devem ser ajustados conforme a estrutura real da sua solução.

Entendendo o funcionamento do pipeline

Vamos analisar os principais pontos da implementação.

1. Configuração dos eventos

on:
  push:
    branches:
      - main
      - develop

  pull_request:
    branches:
      - main
      - develop

Essa configuração determina quando o pipeline será executado.

Sempre que alguém enviar alterações para as branches main ou develop, a automação será iniciada.

O mesmo acontecerá quando uma Pull Request for criada ou atualizada tendo essas branches como destino.

Isso permite validar o código antes de sua integração definitiva.

2. Configuração do ambiente

- name: Setup .NET
  uses: actions/setup-dotnet@v6
  with:
    dotnet-version: '10.0.x'

Aqui utilizamos a Action oficial setup-dotnet para disponibilizar o SDK do .NET 10.

A utilização de uma versão explicitamente configurada evita que o pipeline dependa de uma versão diferente daquela utilizada pelo projeto.

3. Restauração das dependências

- name: Restore dependencies
  run: dotnet restore MinhaAplicacao.sln

Essa etapa restaura os pacotes necessários para todos os projetos da solução.

4. Compilação

- name: Build solution
  run: >
    dotnet build MinhaAplicacao.sln
    --configuration Release
    --no-restore

O parâmetro --configuration Release determina que a compilação será realizada utilizando a configuração Release.

Já o parâmetro --no-restore evita repetir a restauração das dependências, uma vez que essa etapa já foi executada anteriormente.

5. Execução dos testes

- name: Run tests
  run: >
    dotnet test MinhaAplicacao.sln
    --configuration Release
    --no-build

Essa etapa executa os testes automatizados existentes na solução.

O parâmetro --no-build evita uma nova compilação, aproveitando os arquivos gerados anteriormente.

Caso algum teste falhe, o pipeline será interrompido e apresentará o resultado da execução.

6. Publicação da aplicação

- name: Publish application
  run: >
    dotnet publish MinhaAplicacao.Api/MinhaAplicacao.Api.csproj
    --configuration Release
    --no-restore
    --output ./publish

O comando dotnet publish prepara a aplicação para distribuição.

Os arquivos gerados serão armazenados no diretório publish.

7. Armazenamento do artefato

- name: Upload build artifact
  uses: actions/upload-artifact@v4
  with:
    name: minha-aplicacao
    path: ./publish
    retention-days: 7

Por último, utilizamos a Action upload-artifact para armazenar os arquivos publicados como um artefato do pipeline.

Esse pacote poderá ser recuperado posteriormente para realizar o deploy em outro ambiente.

O resultado é um processo automatizado de integração contínua que valida o código e prepara uma versão da aplicação para implantação.

Como adicionar a etapa de deploy ao pipeline?

Até aqui, implementamos um processo de CI que compila, testa e gera um artefato.

Para completar o fluxo de CD, precisamos adicionar uma etapa responsável por disponibilizar a aplicação no ambiente de destino.

Uma arquitetura interessante é separar os processos em dois momentos:

Pipeline de CI:

  • Executa a cada alteração.

  • Compila a solução.

  • Executa os testes.

  • Gera o artefato.

  • Armazena a versão produzida.

Pipeline de CD:

  • Recupera o artefato aprovado.

  • Define o ambiente de destino.

  • Executa as configurações necessárias.

  • Realiza a implantação.

  • Verifica se a aplicação está funcionando.

Por exemplo, podemos configurar um ambiente chamado Production no GitHub Actions.

Esse ambiente pode possuir regras de proteção, como aprovações obrigatórias antes da implantação.

Também é possível armazenar informações sensíveis, como credenciais e configurações de acesso, utilizando os mecanismos de Secrets e Variables.

Uma recomendação importante é evitar armazenar senhas, connection strings ou tokens diretamente nos arquivos YAML ou no código-fonte.

Para aplicações hospedadas no Azure, uma alternativa interessante é utilizar autenticação por OpenID Connect (OIDC), evitando manter credenciais permanentes de acesso à cloud.

Outro cuidado importante é garantir que a implantação utilize exatamente o artefato produzido e validado na etapa de CI, sem realizar uma nova compilação desnecessária.

Boas práticas para criar pipelines eficientes em .NET

Criar um pipeline funcional é apenas o primeiro passo.

Para que ele seja realmente eficiente, precisamos considerar alguns aspectos relacionados à manutenção, segurança e desempenho.

1. Utilize versões controladas do SDK

Evite depender automaticamente da versão mais recente do SDK disponível no agente de execução.

Utilize um arquivo global.json para definir a versão esperada pelo projeto.

Isso ajuda a manter a consistência entre os ambientes de desenvolvimento e automação.

2. Aproveite o cache de pacotes NuGet

A restauração de dependências pode representar uma parte significativa do tempo de execução de um pipeline.

Uma alternativa é utilizar mecanismos de cache para reaproveitar os pacotes já baixados.

No GitHub Actions, o setup-dotnet oferece suporte a cache de dependências NuGet, utilizando arquivos packages.lock.json.

Essa abordagem pode reduzir o tempo gasto na restauração, especialmente em soluções com muitos projetos e dependências.

3. Execute os testes antes do deploy

Nenhuma aplicação deveria ser publicada em produção sem passar pelas validações necessárias.

O pipeline deve interromper o processo quando uma etapa crítica falhar.

Isso evita que uma versão com problemas conhecidos seja disponibilizada aos usuários.

4. Separe os ambientes

Evite utilizar configurações de desenvolvimento diretamente em produção.

Cada ambiente deve possuir suas próprias configurações, credenciais e recursos.

Por exemplo:

Configuração Development Staging Production
Banco de dados Dev DB Homolog DB Prod DB
Logging Debug Information Warning/Information
Dados de teste Sim Controlados Não
Aprovação de deploy Não Opcional Recomendada

A configuração exata dos níveis de logging e dos recursos deve considerar as necessidades de monitoramento da aplicação.

5. Utilize variáveis e Secrets

Informações sensíveis nunca devem ser armazenadas diretamente no repositório.

Utilize os recursos de gerenciamento de Secrets da plataforma de CI/CD.

Isso inclui:

  • Senhas.

  • Tokens de autenticação.

  • Connection strings.

  • Chaves de APIs.

  • Credenciais de cloud.

Sempre que possível, prefira identidades gerenciadas ou mecanismos de autenticação federada.

6. Implemente análise de qualidade

Ferramentas como SonarQube podem complementar o processo de validação.

Elas permitem identificar problemas relacionados a:

  • Complexidade do código.

  • Duplicação.

  • Vulnerabilidades.

  • Code smells.

  • Cobertura de testes.

A análise de qualidade ajuda a evitar que problemas técnicos se acumulem ao longo do desenvolvimento.

7. Configure mecanismos de rollback

Mesmo com um pipeline bem estruturado, problemas podem ocorrer após uma implantação.

Por isso, é importante ter uma estratégia para retornar rapidamente à versão anterior.

Algumas possibilidades incluem:

  • Manter versões anteriores dos artefatos.

  • Utilizar slots de implantação.

  • Trabalhar com versões de containers.

  • Implementar estratégias Blue-Green Deployment.

  • Utilizar Rollback automatizado quando aplicável.

A estratégia deve considerar também possíveis alterações incompatíveis no banco de dados.

8. Monitore a aplicação após a implantação

O processo não termina quando o deploy é concluído.

É importante verificar se a aplicação está respondendo corretamente.

Podemos utilizar:

  • Health Checks.

  • Logs estruturados.

  • Application Insights.

  • Alertas de disponibilidade.

  • Monitoramento de erros e desempenho.

Essas informações permitem identificar rapidamente problemas que não foram detectados durante os testes automatizados.

E quanto aos projetos .NET Framework?

Embora os exemplos apresentados utilizem .NET 10, os conceitos de CI/CD também se aplicam a projetos desenvolvidos com .NET Framework.

Entretanto, existem algumas diferenças importantes.

Projetos .NET Framework normalmente possuem dependências de componentes do Windows e versões específicas do Visual Studio Build Tools.

Por esse motivo, pode ser necessário utilizar agentes Windows na execução do pipeline.

Além disso, dependendo da estrutura do projeto, a compilação pode exigir ferramentas como MSBuild e procedimentos específicos para publicação de aplicações ASP.NET tradicionais.

O ponto principal é entender que CI/CD não está limitado a aplicações desenvolvidas com .NET moderno.

Mesmo sistemas legados podem se beneficiar da automação de compilação, testes e implantação.

Conclusão

A implementação de CI/CD representa um passo importante para melhorar a qualidade e a eficiência do desenvolvimento de software.

No ecossistema .NET, ferramentas como GitHub Actions e Azure DevOps permitem automatizar praticamente todas as etapas necessárias para validar, preparar e disponibilizar uma aplicação.

Começar com um pipeline simples, contendo restauração de dependências, compilação e testes automatizados, já proporciona benefícios significativos.

À medida que o projeto evolui, podemos adicionar análise de qualidade, geração de artefatos, implantação automatizada, aprovações e monitoramento.

O mais importante é construir um processo consistente, seguro e adequado à realidade da equipe.

Com um pipeline bem estruturado, os desenvolvedores conseguem reduzir tarefas manuais, identificar problemas mais rapidamente e entregar novas funcionalidades com maior confiança.

Se você trabalha com C# e .NET, vale a pena começar a implementar essas práticas nos seus projetos. Mesmo uma pequena automação pode fazer uma grande diferença no processo de desenvolvimento.