# CI/CD

> Build, publish and deploy TX Text Control apps in pipelines: feed credentials, publishing for win-x64 or linux-x64, artifacts, Azure deployment and images.

- **Product:** TX Text Control .NET Server
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET Server > Deployment Guide > CI/CD
- **2066 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/ci-cd/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/ci-cd/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/ci-cd/llms-full.txt

---

A pipeline for an application with TX Text Control .NET Server is an ordinary .NET pipeline with three additions: the credentials for the Text Control Private NuGet Feed, a publish step for the runtime the application runs on and, for containers, an image build that keeps the credentials out of the image. Everything else, from tests to deployment slots, works as in any other .NET project.

The restore from the private feed is described step by step in [CI/CD Authentication](https://docs.textcontrol.com/tx-text-control-dotnet-server/installation/nuget/private-feed/ci-cd/llms-full.txt), for GitHub Actions, GitLab, Azure DevOps, Jenkins, Bitbucket and TeamCity. The sections below continue where those pipelines end: with publishing, artifacts and deployment.

### What Build Servers Need

- **The feed credentials as secrets.** The pipeline writes *nuget.config* from the secrets before the first `dotnet` command, as [CI/CD Authentication](https://docs.textcontrol.com/tx-text-control-dotnet-server/installation/nuget/private-feed/ci-cd/#how-it-works) shows. Write the file to the root of the repository, above the project folders.
- **No license for the build server.** TX Text Control is licensed per developer, not per build server. See [Build Servers and CI/CD](https://docs.textcontrol.com/tx-text-control-dotnet-server/installation/licensing/development/#build-servers-and-ci-cd).
- **An x64 agent on Windows or Linux** for tests that use `ServerTextControl`. The Core package contains native libraries for `win-x64` and `linux-x64` only, so such tests don't run on macOS or ARM64 agents. On Linux, the agent must meet the [Linux Requirements](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/linux/requirements/llms-full.txt).

### Publish for the Target Runtime

Publish the application for the runtime identifier of the servers it runs on:

```bash
dotnet publish MyApp/MyApp.csproj -c Release -r linux-x64 --self-contained false -o publish
```

Use `-r win-x64` for Windows servers and Azure App Service on Windows. The command works as follows:

- **`-r linux-x64`** puts the native libraries of that platform next to the application, together with the *Fonts* folder of the Core engine and the files of the Document Editor backend. Without a runtime identifier, the output contains the native libraries of all platforms in a *runtimes* folder.
- **`--self-contained false`** leaves out the .NET runtime, which the servers or App Service provide. Text Control's publishing examples use framework-dependent deployments. The Document Editor backend runs as a separate process with the installed .NET runtime in any case.
- **`dotnet publish` restores the packages again** for the runtime identifier. Keep *nuget.config* in place until the publish step has run, or restore with `-r linux-x64` beforehand and publish with `--no-restore`.

Don't write *nuget.config* into the project folder. A web project copies *.config* files from its folder into the publish output, and an artifact or a deployed package would then contain the API token of the feed. In the root of the repository, `dotnet restore` still finds the file.

### Upload the Output as an Artifact

In GitHub Actions, add a publish step and an upload step after the test step of the workflow from [CI/CD Authentication](https://docs.textcontrol.com/tx-text-control-dotnet-server/installation/nuget/private-feed/ci-cd/#github-actions):

```yaml
      - name: Publish
        run: dotnet publish MyApp/MyApp.csproj -c Release -r linux-x64 --self-contained false -o publish

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: myapp
          path: publish
```

A later job or workflow deploys the artifact. For Azure App Service, Microsoft describes the sign-in and deployment steps in [Deploy to App Service using GitHub Actions](https://learn.microsoft.com/en-us/azure/app-service/deploy-github-actions).

### Deploy to Azure App Service With Azure Pipelines

In Azure Pipelines, the .NET Core task publishes the web project into a ZIP file, and the Azure Web App task deploys it. Add both tasks after the restore of the pipeline from [CI/CD Authentication](https://docs.textcontrol.com/tx-text-control-dotnet-server/installation/nuget/private-feed/ci-cd/#azure-devops):

```yaml
  - task: DotNetCoreCLI@2
    displayName: 'Publish'
    inputs:
      command: 'publish'
      publishWebProjects: true
      arguments: '--configuration Release -r linux-x64 --self-contained false'
      zipAfterPublish: true

  - task: AzureWebApp@1
    displayName: 'Deploy'
    inputs:
      azureSubscription: '<service-connection-name>'
      appType: 'webAppLinux'
      appName: '<app-name>'
      package: '$(System.DefaultWorkingDirectory)/**/*.zip'
```

The tasks work as follows:

- **`arguments`** passes the runtime identifier to `dotnet publish`. For App Service on Windows, use `-r win-x64` and set `appType` to `webApp`.
- **`azureSubscription`** is the name of an authorized service connection to your Azure subscription.
- **`package`** finds the ZIP file that the publish task created.

App Service on Windows needs the 64-bit platform and Web sockets before the first deployment. [Azure App Service Windows](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/azure/app-service-windows/llms-full.txt) describes these settings, and Microsoft's article [Configure CI/CD with Azure Pipelines](https://learn.microsoft.com/en-us/azure/app-service/deploy-azure-pipelines) covers deployment slots and approvals.

### Build a Container Image in the Pipeline

For containers, the pipeline builds the image with the Dockerfile from [Dockerfile](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/docker/dockerfile/llms-full.txt) and passes the generated *nuget.config* as a build secret:

```bash
docker buildx build --secret id=nugetconfig,src=nuget.config -t myregistry.example.com/myapp:1.0.0 .
docker push myregistry.example.com/myapp:1.0.0
```

The Dockerfile restores and publishes inside the build, so the pipeline needs no `dotnet` steps of its own for the image. The secret is available only during the restore and isn't part of any image layer. Sign in to your registry before `docker push`, as your registry requires.

### Check Templates Before Deployment

Templates that reach a server can depend on fonts, images and data fields that exist only on a developer machine. The sample project [TXTextControl.Check.Dependencies](https://github.com/TextControl/TXTextControl.Check.Dependencies) loads a template with `ServerTextControl` and reports missing fonts, linked images that don't exist and fields or blocks of the JSON data that the template doesn't contain as merge fields, merge blocks or form fields. The blog article [Check TX Text Control Template Dependencies Before Deployment](https://www.textcontrol.com/blog/2026/07/28/check-tx-text-control-template-dependencies-before-deployment/) suggests running such a check in a pipeline with the same package version and *Fonts* folder as production. The sample prints its results and doesn't set an exit code, so add one if the check should stop a pipeline.

### Keep the Versions Consistent

- **NuGet packages.** Reference `TXTextControl.TextControl.Core.SDK`, `TXTextControl.Web` and `TXTextControl.Web.DocumentEditor.Backend` explicitly: the backend and web packages don't declare a dependency on the Core package. Pin the versions, so that every build restores the same packages; see [Package Versioning](https://docs.textcontrol.com/tx-text-control-dotnet-server/installation/nuget/versioning/llms-full.txt).
- **npm packages.** Angular and React frontends use npm packages whose major version must match the major version of TX Text Control .NET Server on the backend. Update both together, as [Updating npm Packages](https://docs.textcontrol.com/tx-text-control-dotnet-server/installation/upgrading/npm/llms-full.txt) describes.

### Next Steps

- [CI/CD Authentication](https://docs.textcontrol.com/tx-text-control-dotnet-server/installation/nuget/private-feed/ci-cd/llms-full.txt): restore the packages in each CI system.
- [Dockerfile](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/docker/dockerfile/llms-full.txt): the image that a pipeline builds.
- [Azure](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/azure/llms-full.txt): the App Service settings for TX Text Control.
- [NuGet Authentication](https://docs.textcontrol.com/tx-text-control-dotnet-server/troubleshooting/nuget-authentication/llms-full.txt): solve restore problems on build servers.

---

## Nearby

- **Previous:** [Google Cloud](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/google-cloud/llms-full.txt)
- **Next:** [Security](https://docs.textcontrol.com/tx-text-control-dotnet-server/security/llms-full.txt)
