Temporal is a distributed, scalable, durable, and highly available orchestration engine used to execute asynchronous, long-running business logic in a scalable and resilient way.
This repository contains the Temporal .NET SDK, the framework for authoring workflows and activities using .NET programming languages, along with its extension packages.
To install and use the SDK, see the Temporalio package README. It covers the quick
start, clients, workers, workflows, activities, Nexus, and testing.
Also see:
Contents
Each package has its own README next to its project, which is also its NuGet package page.
| Package | Description |
|---|---|
| Temporalio | The core SDK: clients, workers, workflows, activities, and Nexus operations |
| Temporalio.Extensions.Aws.Lambda | Running a worker inside an AWS Lambda invocation |
| Temporalio.Extensions.Aws.Lambda.OpenTelemetry | OpenTelemetry helpers for workers running in AWS Lambda |
| Temporalio.Extensions.DiagnosticSource | System.Diagnostics.Metrics support for SDK metrics |
| Temporalio.Extensions.Gcp.CloudRun.Id | Client identity derived from Google Cloud Run instance metadata |
| Temporalio.Extensions.Gcp.CloudRun.OpenTelemetry | OpenTelemetry defaults for workers running on Google Cloud Run |
| Temporalio.Extensions.Hosting | Client dependency injection, activity dependency injection, and worker generic host support |
| Temporalio.Extensions.OpenTelemetry | OpenTelemetry tracing support |
| Temporalio.Extensions.WorkflowStreams | Experimental durable, offset-based workflow publish/subscribe streams |
See CONTRIBUTING.md for how to open issues and pull requests, and the Development section below for building and testing this repository.
Prerequisites:
- .NET SDK — version pinned in
global.json - Rust (i.e.
cargoon thePATH) — installing via rustup is recommended, since the toolchain version is pinned insrc/Temporalio/Bridge/rust-toolchain.tomland only rustup honors that pin - Protobuf Compiler (i.e.
protocon thePATH) - mise — running
mise installin the repository root installs the tool versions pinned inmise.tomland puts them on thePATH, matching what CI uses. It also installs the .NET SDK pinned inglobal.json, so installing .NET separately is optional - This repository, cloned recursively
With all prerequisites in place, run:
dotnet build
Or for release:
dotnet build --configuration Release
The native Rust library is built automatically as part of the above, through the Cargo workspace at
src/Temporalio/Bridge/Cargo.toml. That workspace exists so the
library's dependency graph is pinned by a committed
Cargo.lock; sdk-core is a published Rust library and
deliberately does not commit one of its own. Its workspace tables and toolchain channel are
mirrored from the submodule. Update Core with mise run core:update, which also imports its
changelog entries as fragments. See CONTRIBUTING.md for the
full process. Copy over anything that changed upstream and then run:
mise run bridge:check-sync # confirm the mirrored tables match the submodule
mise run bridge:relock # refresh Bridge/Cargo.lock, then commit it
This project uses StyleCop analyzers with some overrides in .editorconfig. To format, run:
dotnet format
Can also run with --verify-no-changes to ensure it is formatted.
When developing in vscode, the following JSON settings will enable StyleCop analyzers:
"omnisharp.enableEditorConfigSupport": true,
"omnisharp.enableRoslynAnalyzers": trueRun:
dotnet test
Can add options like:
--logger "console;verbosity=detailed"to show logs--filter "FullyQualifiedName=Temporalio.Tests.Client.TemporalClientTests.ConnectAsync_Connection_Succeeds"to run a specific test--blame-crashto do a host process dump on crash
To help debug native pieces and show full stdout/stderr, this is also available as an in-proc test program. Run:
dotnet run --project tests/Temporalio.Tests
Extra args can be added after --, e.g. -- -verbose would show verbose logs and -- --help would show other
options. If the arguments are anything but --help, the current assembly is prepended to the args before sending to the
xUnit runner.
Tests are eligible to run against Temporal Cloud unless they have a CloudTestExclusion attribute. Run or list the
Cloud-eligible tests with:
dotnet test tests/Temporalio.Tests --filter "CloudTest!=Excluded"
dotnet test tests/Temporalio.Tests --list-tests --filter "CloudTest!=Excluded"
To inventory excluded tests, filter on CloudTest=Excluded, or filter on
CloudTestExclusionReason to inspect a particular category.
The following environment variables can be set to override the environment:
TEMPORAL_TEST_CLIENT_TARGET_HOST- This must be set for any of the variables below to applyTEMPORAL_TEST_CLIENT_NAMESPACE- Required if the above is setTEMPORAL_TEST_CLIENT_CERT- Optional, must be present if below isTEMPORAL_TEST_CLIENT_KEY- Optional, must be present if above is
Every generator is a mise task. The .NET tools they need are pinned in
.config/dotnet-tools.json and the rest in mise.toml. To regenerate
everything the way CI does:
mise run gen
Or regenerate a single piece:
mise run gen:api- theTemporalio.Api.*protobuf typesmise run gen:nexus- the system Nexus workflow service bindingsmise run gen:interop- the bridge interop layer, from thesdk-coreC header, using ClangSharpPInvokeGenerator
Each task installs the tools it needs on first run, so nothing has to be installed globally. Run mise tasks to see
them all. Commit the regenerated output rather than hand-editing generated files; CI runs mise run gen and fails if
it produces a diff.
gen:interop runs on Windows only, because the generator package ships native libclang binaries for Windows alone
(it can be made to work on Linux, but it is annoying to set up). It is ordered last so the other generators still
complete elsewhere.
If you cannot run a generator locally, let CI produce the output for you. The "Regen confirm unchanged" step uploads a
generator-diff artifact holding a single generator.diff, a unified diff of everything the regen changed. From the
repository root:
gh run download <run-id> -n generator-diff
git apply generator.diff
The artifact can also be downloaded as a zip from the Artifacts section of the workflow run page. Review the result and commit it as you would your own regen.
The Rust DLL itself is built automatically when the project is built, and needs protoc on the PATH (see
Build).
mise run docs
This builds the docs with docfx at the version pinned in
.config/dotnet-tools.json.
