# Standalone Activities .NET quickstart

> For the complete documentation index, see [llms.txt](https://docs.temporal.io/llms.txt).
> Any documentation page is available as raw Markdown by appending `.md` to its URL.
> For related questions, query https://docs.temporal.io/api/retrieve?q=<question>&jtb=<job-to-be-done>&src=md-page&agent=<your-name> (no auth; returns JSON `{content, source_url, page_url}`, with `source_url` pointing to Markdown for docs pages). Don't include personal data or credentials.

> Execute a Standalone Activity with the Temporal .NET SDK without writing a Workflow.

# Quickstart

Standalone Activities are Activities that run independently, without being orchestrated by a
Workflow. Instead of starting an Activity from within a Workflow Definition, you start a Standalone
Activity directly from a Temporal Client.

The way you write the Activity and register it with a Worker is identical to [Workflow
Activities](/develop/dotnet/activities/basics#develop-activity). The only difference is that you execute a
Standalone Activity directly from your Temporal Client.

> **📝 Note:**
>
> This documentation uses source code from the [StandaloneActivities](https://github.com/temporalio/documentation-sdk-code-examples/tree/main/dotnet-sandbox/activities/StandaloneActivities) sample project.
>

## Get started with Standalone Activities 

Prerequisites:

- **[.NET](https://dotnet.microsoft.com/download)** 10.0+ for the sample project
  (the Temporal .NET SDK requires .NET Core 3.1+, Framework 4.6.2+, or Standard 2.0+)

- **Temporal .NET SDK** (v1.19.0 or higher). See the [.NET Quickstart](/develop/dotnet/set-up-your-local-dotnet) for install instructions.

- **Temporal CLI** v1.9.1 or higher. Install with Homebrew, or see the [Temporal CLI install guide](/cli/setup-cli) for other platforms. Verify the installation with `temporal --version`.

Start the Temporal development server with `temporal server start-dev`.

This command automatically starts the Temporal development server with the Web UI, and creates the `default` Namespace.
It uses an in-memory database, so do not use it for real use cases.

The Temporal Server will now be available for client connections on `localhost:7233`, and the
Temporal Web UI will now be accessible at [http://localhost:8233](http://localhost:8233).

```bash
brew install temporal
```

```bash
temporal --version
```

```bash
temporal server start-dev
```

## Clone the sample

Clone the [documentation-sdk-code-examples](https://github.com/temporalio/documentation-sdk-code-examples) repository to follow along:

```
git clone https://github.com/temporalio/documentation-sdk-code-examples.git
cd documentation-sdk-code-examples/dotnet-sandbox
```

The sample project is structured as follows:

```
activities/StandaloneActivities/
├── ExecuteActivityExamples.cs
├── MyActivities.cs
├── Program.cs
├── StandaloneActivities.csproj
├── StandaloneClient.cs
└── StandaloneWorker.cs
```

<!--SNIPSTART dotnet-standalone-activities-define-->
[dotnet-sandbox/activities/StandaloneActivities/MyActivities.cs](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/dotnet-sandbox/activities/StandaloneActivities/MyActivities.cs)
```cs
namespace TemporalioDocs.Activities.StandaloneActivities;

using Temporalio.Activities;

public static class MyActivities
{
    [Activity]
    public static Task<string> ComposeGreetingAsync(ComposeGreetingInput input) =>
        Task.FromResult($"{input.Greeting}, {input.Name}!");
}

public record ComposeGreetingInput(string Greeting, string Name);
```
<!--SNIPEND-->

## Define your Activity 

An Activity in the Temporal .NET SDK is a method decorated with the `[Activity]` attribute. The way
you write a Standalone Activity is identical to how you write an Activity orchestrated by a Workflow.
In fact, the same Activity can be executed both as a Standalone Activity and as a Workflow Activity.

<!--SNIPSTART dotnet-standalone-activities-worker-->
[dotnet-sandbox/activities/StandaloneActivities/StandaloneWorker.cs](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/dotnet-sandbox/activities/StandaloneActivities/StandaloneWorker.cs)
```cs
using Microsoft.Extensions.Logging;
using Temporalio.Client;
using Temporalio.Common.EnvConfig;
using Temporalio.Worker;

public static class StandaloneWorker
{
    public static async Task RunAsync()
    {
        var connectOptions = ClientEnvConfig.LoadClientConnectOptions();
        connectOptions.TargetHost ??= "localhost:7233";
        connectOptions.LoggerFactory = LoggerFactory.Create(builder =>
            builder.
                AddSimpleConsole(options => options.TimestampFormat = "[HH:mm:ss] ").
                SetMinimumLevel(LogLevel.Information));
        var client = await TemporalClient.ConnectAsync(connectOptions);

        const string taskQueue = "standalone-activity-sample";

        using var tokenSource = new CancellationTokenSource();
        Console.CancelKeyPress += (_, eventArgs) =>
        {
            tokenSource.Cancel();
            eventArgs.Cancel = true;
        };

        using var worker = new TemporalWorker(
            client,
            new TemporalWorkerOptions(taskQueue).
                AddActivity(MyActivities.ComposeGreetingAsync));

        await worker.ExecuteAsync(tokenSource.Token);
    }
}
```
<!--SNIPEND-->

```bash
dotnet run --project activities/StandaloneActivities worker
```

## Run a Worker with the Activity registered 

Running a Worker for Standalone Activities is the same as running a Worker for Workflow Activities —
you create a Worker, register the Activity, and run the Worker. The Worker doesn't need to know
whether the Activity will be invoked from a Workflow or as a Standalone Activity. See
[Develop a Worker](/develop/dotnet/workers/run-worker-process) for more details on Worker setup and configuration
options.

Open a new terminal, navigate to the `dotnet-sandbox` directory, and run the Worker.
Leave this terminal running - the Worker needs to stay up to process activities.

<!--SNIPSTART dotnet-standalone-activities-execute-->
[dotnet-sandbox/activities/StandaloneActivities/StandaloneClient.cs](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/dotnet-sandbox/activities/StandaloneActivities/StandaloneClient.cs)
```cs
using Temporalio.Client;
using Temporalio.Common.EnvConfig;

public static class StandaloneClient
{
    public static async Task RunAsync()
    {
        var connectOptions = ClientEnvConfig.LoadClientConnectOptions();
        connectOptions.TargetHost ??= "localhost:7233";
        var client = await TemporalClient.ConnectAsync(connectOptions);

        var result = await client.ExecuteActivityAsync(
            () => MyActivities.ComposeGreetingAsync(new ComposeGreetingInput("Hello", "World")),
            new("standalone-activity-id", "standalone-activity-sample")
            {
                ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
            });
        Console.WriteLine($"Activity result: {result}");
    }
}
```
<!--SNIPEND-->

<!--SNIPSTART dotnet-standalone-activities-execute-options-->
[dotnet-sandbox/activities/StandaloneActivities/ExecuteActivityExamples.cs](https://github.com/temporalio/documentation-sdk-code-examples/blob/main/dotnet-sandbox/activities/StandaloneActivities/ExecuteActivityExamples.cs)
```cs
// Using a lambda expression (type-safe)
var result = await client.ExecuteActivityAsync(
    () => MyActivities.ComposeGreetingAsync(new ComposeGreetingInput("Hello", "World")),
    new("standalone-activity-id", "standalone-activity-sample")
    {
        ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
    });

// Using a string type name
var resultByName = await client.ExecuteActivityAsync<string>(
    "ComposeGreeting",
    new object?[] { new ComposeGreetingInput("Hello", "World") },
    new("standalone-activity-id", "standalone-activity-sample")
    {
        ScheduleToCloseTimeout = TimeSpan.FromSeconds(10),
    });
```
<!--SNIPEND-->

```bash
dotnet run --project activities/StandaloneActivities execute-activity
```

```bash
temporal activity execute \\
  --type ComposeGreeting \\
  --activity-id standalone-activity-id \\
  --task-queue standalone-activity-sample \\
  --schedule-to-close-timeout 10s \\
  --input '{"Greeting": "Hello", "Name": "World"}'
```

## Execute a Standalone Activity 

Use
[`client.ExecuteActivityAsync()`](https://dotnet.temporal.io/api/Temporalio.Client.ITemporalClientExtensions.html)
to execute a Standalone Activity and wait for the result. Call this from your application code, not
from inside a Workflow Definition. This durably enqueues your Standalone Activity in the Temporal
Server, waits for it to be executed on your Worker, and then returns the result.

You can pass the Activity as either a lambda expression or a string Activity type name.

`StartActivityOptions` requires `Id`, `TaskQueue`, and at least one of `ScheduleToCloseTimeout` or
`StartToCloseTimeout`. See
[`StartActivityOptions`](https://dotnet.temporal.io/api/Temporalio.Client.StartActivityOptions.html)
in the API reference for the full set of options.

To run it:

1. Make sure the Temporal Server is running (from the [Get Started](#get-started) step above).
2. Make sure the Worker is running (from the [Run a Worker](#run-worker) step above).
3. Open a new terminal, navigate to the `dotnet-sandbox` directory, and run:
    ```
    dotnet run --project activities/StandaloneActivities execute-activity
    ```

Or use the Temporal CLI.

## Run with Temporal Cloud

All code samples on this page use
[`ClientEnvConfig.LoadClientConnectOptions()`](https://dotnet.temporal.io/api/Temporalio.Common.EnvConfig.ClientEnvConfig.html)
to configure the Temporal Client connection. It responds to [environment
variables](/references/client-environment-configuration) and [TOML configuration
files](/references/client-environment-configuration), so the same code works against a local dev
server and Temporal Cloud without changes. See [Run Standalone Activities with Temporal
Cloud](/develop/dotnet/activities/standalone-activities#run-standalone-activities-temporal-cloud) in the feature guide
for mTLS and API key setup.

## Next steps

- **[Standalone Activities feature guide](/develop/dotnet/activities/standalone-activities)**: Start without waiting, get handles, list and count Activities, and connect to Temporal Cloud.
- **[Activity basics](/develop/dotnet/activities/basics)**: Write and register Activities with the .NET SDK.
