# ...
    spec:
      containers:
        - args:
            - -k
            - supersecretkey
            - -s
            - billing
          env:
            - name: FRAUD_API_URL
              value: http://billing-api:8084
            - name: TEMPORAL_ADDRESS
              value: temporal-frontend.temporal:7233
          image: ghcr.io/temporalio/reference-app-orders-go-worker:latest
          name: billing-worker
          imagePullPolicy: Always
      enableServiceLinks: false
```
{/* SNIPEND */}

### Separate Task Queues logically

Use separate Task Queues for distinct workloads. This isolation allows you to control rate limiting, prioritize certain
workloads, and prevent one workload from starving another. For each Task Queue, ensure you configure at least two
Workers to poll the Task Queue.

In the order management reference app, each microservice has its own Task Queue. For example, the Billing Worker polls
the `billing` Task Queue, while the Order Worker polls the `order` Task Queue. This separation allows each service to
scale independently based on its workload.

<CaptionedImage
  src="/diagrams/worker-best-practice-oms-architecture.png"
  title="Diagram showing separate Task Queues for different Workers"
/>

The following code snippet shows how the Billing Worker is set up to poll its Task Queue. The default value for
`TaskQueue` is a constant defined in the `api.go` configuration file and is set to `billing`.

Since Task Queues are created dynamically when first used, a mismatch between the Client and Worker Task Queue names
does not result in an error. Instead, it creates two different Task Queues, and the Worker never receives Tasks from the
Temporal Service because it's polling the wrong queue. Define the Task Queue name as a constant that both the Client and
Worker reference to avoid this issue.

{/* SNIPSTART oms-billing-worker-go {"selectedLines": ["12-23"]} */}
[app/billing/worker.go](https://github.com/temporalio/reference-app-orders-go/blob/main/app/billing/worker.go)
```go
// ...
// RunWorker runs a Workflow and Activity worker for the Billing system.
func RunWorker(ctx context.Context, config config.AppConfig, client client.Client) error {
	w := worker.New(client, TaskQueue, worker.Options{
		MaxConcurrentWorkflowTaskPollers: 8,
		MaxConcurrentActivityTaskPollers: 8,
	})

	w.RegisterWorkflow(Charge)
	w.RegisterActivity(&Activities{FraudCheckURL: config.FraudURL})

	return w.Run(temporalutil.WorkerInterruptFromContext(ctx))
}
```
{/* SNIPEND */}

### Use Worker Versioning to safely deploy new Workflow code

Use Worker Versioning to deploy new Workflow code without breaking running Executions. Worker Versioning lets you map
each Workflow Execution to a specific Worker Deployment Version identified by a build ID, which guarantees that pinned
Workflows always run on the same Worker version where they started.

For most teams, Worker Versioning should be the default approach for evolving Workflow code in production. It gives you
safer rollouts, clearer rollback behavior, and a cleaner operational model than maintaining multiple code paths inside a
Workflow definition.

To learn more about versioning Workflows, see the
[Workflow Versioning](/production-deployment/worker-deployments/worker-versioning.mdx) guide or take our
[Worker Versioning course](https://learn.temporal.io/courses/worker_versioning/).

:::tip

If your deployment environment cannot yet support Worker Versioning, you can use [Patching](/patching) to introduce
changes to your Workflow code without breaking running Executions. Treat patching as a fallback for environments that
cannot adopt versioned worker deployments yet, not as the default recommendation.

:::

### Manage Event History growth

If a Worker goes offline and another Worker picks up the same Workflow Execution, the new Worker must replay the
existing Event History to resume the Workflow Execution. If the Event History is too large or has too many Events,
replay affects the performance of the new Worker and may even cause timeout errors well before the hard limit of 51,200
Events is reached.

We recommend not exceeding a few thousand Events in a single Workflow Execution. The best way to handle Event History
growth is to use the [Continue-As-New](/workflow-execution/continue-as-new) mechanism to continue under a new Workflow
Execution with a new Event History, repeating this process as you approach the limits again.

All Temporal SDKs provide functions to suggest when to use [Continue-As-New](/workflow-execution/continue-as-new). For
example, the Python SDK has the
[`is_continue_as_new_suggested()`](https://python.temporal.io/temporalio.workflow.Info.html#is_continue_as_new_suggested)
function that returns a `bool` indicating whether to use Continue-As-New.

In addition to the number of Events, monitor the size of the Event History. Input parameters and output values of both
Workflows and Activities are stored in the Event History. Storing large amounts of data can lead to performance
problems, so the Temporal Cluster limits both the size of individual payloads and the total Event History size. A
Workflow Execution may be terminated if any single payload exceeds 2 MB or if the entire Event History exceeds 50 MB.

To avoid hitting these limits, avoid passing large amounts of data into and out of Workflows and Activities. A common
way to reduce payload and Event History size is the
[Claim Check](https://dataengineering.wiki/Concepts/Software+Engineering/Claim+Check+Pattern) pattern, widely used with
messaging systems such as Apache Kafka. Instead of passing large data into your function, store that data external to
Temporal in a database or file system. Pass an identifier for the data, such as a primary key or path, into the function
and use an Activity to retrieve it as needed. If your Activity produces large output, use a similar approach: write the
data to an external system and return an identifier that can be used to retrieve it later.

## Scaling, monitoring, and tuning

Scaling and tuning are critical to Worker performance and cost efficiency. The goal is to balance concurrency,
throughput, and resource utilization while maintaining low Task latency.

### Actively tune Worker options instead of relying on defaults

Default Worker settings are designed to work across a wide range of use cases primarily for ease in development and
testing. In production environments, your Workflow complexity, Activity duration, payload sizes, and infrastructure
constraints all influence optimal Worker configuration. Actively tuning your Workers ensures they perform well under
your specific workload conditions.

To get started, focus on these key Worker options:

- **Task slots**: Limits how many Tasks execute concurrently. Set based on your Worker's CPU, memory, and the resource
  demands of your code. You can choose different types of Slot Suppliers or implement a custom Slot Supplier to control
  how Task slots are assigned to different Task types. Refer to
  [Slot Suppliers](/develop/worker-performance#slot-suppliers) for more details.
- **Sticky cache size**: Controls the size of the sticky cache for Workflow Executions. Larger caches reduce replay
  overhead but consume more memory. Refer to [Workflow Cache Tuning](/develop/worker-performance#workflow-cache-tuning)
  for more details.
- **Poller counts**: Controls the number of pollers for Tasks. We recommend you use the Poller Autoscaling feature to
  automatically adjust the number of pollers based on your workload. Refer to
  [Configuring Poller Options](/develop/worker-performance#configuring-poller-options) for more details.

Use the metrics listed in [Interpret metrics as a whole](#interpret-metrics-as-a-whole) to guide your tuning decisions.

### Interpret metrics as a whole

No single metric tells the full story. The following are some of the most useful Worker-related metrics to monitor. We
recommend having all metrics listed below on your Worker monitoring dashboard. When you observe anomalies, correlate
across multiple metrics to identify root causes.

- Worker CPU and memory utilization
- `workflow_task_schedule_to_start_latency` and `activity_task_schedule_to_start_latency`
- `worker_task_slots_available`
- `temporal_long_request_failure`, `temporal_request_failure`, `temporal_long_request_latency`, and
  `temporal_request_latency`

For example, Schedule-to-Start latency measures how long a Task waits in the queue before a Worker starts it. High
latency means your Workers or pollers can’t keep up with incoming Tasks, but the root cause depends on your resource
metrics:

- High Schedule-to-Start latency and high CPU/memory: Workers are saturated. Scale up your Workers or add more Workers.
  It's also possible your Workers are blocked on Activities. Refer to
  [Troubleshooting - Depletion of Activity Task Slots](../troubleshooting/performance-bottlenecks.mdx#depletion-of-temporal_worker_task_slots_available-for-activityworker)
  for guidance.
- High Schedule-to-Start latency and low CPU/memory: Workers are underutilized. Increase the number of pollers, executor
  slots, or both. If this is accompanied by high `temporal_long_request_latency` or `temporal_long_request_failure`,
  your Workers are struggling to reach the Temporal Service. Refer to
  [Troubleshooting - Long Request Latency](../troubleshooting/performance-bottlenecks.mdx#high-temporal_long_request_failure)
  for guidance.
- Low Schedule-to-Start latency and low CPU/memory: Depending on your workload, this could be normal. If you are
  consistently seeing low memory usage and low CPU usage, you may be over-provisioning your Workers and can consider
  scaling down.

Refer to [Intro to Worker Tuning](https://temporal.io/blog/an-introduction-to-worker-tuning) for more details and
examples on how to interpret Worker metrics.

### Optimize Worker cache

Workers keep a cache of Workflow Executions to improve performance by reducing replay overhead. However, larger caches
consume more memory. The `temporal_sticky_cache_size` tracks the size of the cache. If you observe high memory usage for
your Workers and high `temporal_sticky_cache_size`, you can be reasonably sure the cache is contributing to memory
pressure.

Having a high `temporal_sticky_cache_size` by itself isn't necessarily an issue, but if your Workers are memory-bound,
consider reducing the cache size to allow more concurrent executions. We recommend you experiment with different cache
sizes in a staging environment to find the optimal setting for your Workflows. Refer to
[Troubleshooting - Caching](../troubleshooting/performance-bottlenecks.mdx#caching) for more details on how to interpret
the different cache-related metrics.

### Manage scale-down safely

Before shutting down a Worker, verify that it does not have too many active Tasks. This is especially relevant if your
Workers are handling long-running, expensive Activities.

If `worker_task_slots_available` is at or near zero, the Worker is running active Tasks. Shutting it down could trigger
expensive retries or timeouts for long-running Activities. Use
[Graceful Shutdowns](/encyclopedia/workers/worker-shutdown#graceful-shutdown) to allow the Worker to complete its
current Tasks before shutting down. All SDKs provide a way to configure Graceful Shutdowns. For example, the Go SDK has
the [`WorkerStopTimeout` option](https://pkg.go.dev/go.temporal.io/sdk@v1.38.0/internal#WorkerOptions) that lets you
configure how long the Worker has to complete its current Tasks before shutting down.

---

## CLI basics

This page walks through the operations you're most likely to reach for when using the Temporal CLI. For the full set of
commands, see the [command reference](/cli#command-reference).

<SetupSteps>
<SetupStep code={
<>
<CodeSnippet language="bash">
temporal server start-dev
</CodeSnippet>
<CodeSnippet language="bash">
temporal server start-dev --db-filename temporal.db
</CodeSnippet>
</>
}>

## Run a development server

The Temporal CLI ships with a complete Temporal binary. Start a local Temporal Service for development with a single
command.

The Temporal Service is available on `localhost:7233` and the Web UI at `http://localhost:8233`.

To keep Workflow data between restarts, specify a database file.

See [Install and configure](/cli/setup-cli#run-a-local-development-server) for more development server options.

</SetupStep>

<SetupStep code={
<>
<CodeSnippet language="bash">
{`temporal workflow start \\
  --task-queue my-task-queue \\
  --type MyWorkflow \\
  --workflow-id my-workflow-id \\
  --input '"my-input-value"'`}
</CodeSnippet>
<CodeSnippet language="bash">
{`temporal workflow execute \\
  --task-queue my-task-queue \\
  --type MyWorkflow \\
  --workflow-id my-workflow-id \\
  --input '"my-input-value"'`}
</CodeSnippet>
</>
}>

## Start a Workflow

Start a Workflow Execution with `temporal workflow start`.

To start a Workflow and wait for the result, use `temporal workflow execute` instead.

</SetupStep>

<SetupStep code={
<>
<CodeSnippet language="bash">
temporal workflow list
</CodeSnippet>
<CodeSnippet language="bash">
temporal workflow describe --workflow-id my-workflow-id
</CodeSnippet>
<CodeSnippet language="bash">
temporal workflow show --workflow-id my-workflow-id
</CodeSnippet>
</>
}>

## Check Workflow status

List running Workflows.

Get details about a specific Workflow Execution.

View the Event History for a Workflow Execution.

</SetupStep>

<SetupStep code={
<>
<CodeSnippet language="bash">
{`temporal workflow signal \\
  --workflow-id my-workflow-id \\
  --name my-signal \\
  --input '"signal-value"'`}
</CodeSnippet>
<CodeSnippet language="bash">
{`temporal workflow query \\
  --workflow-id my-workflow-id \\
  --name my-query`}
</CodeSnippet>
</>
}>

## Send Signals and Queries

Send a [Signal](/sending-messages#sending-signals) to a running Workflow.

[Query](/sending-messages#sending-queries) a running Workflow for its current state.

</SetupStep>

<SetupStep code={
<>
<CodeSnippet language="bash">
temporal workflow cancel --workflow-id my-workflow-id
</CodeSnippet>
<CodeSnippet language="bash">
temporal workflow terminate --workflow-id my-workflow-id
</CodeSnippet>
</>
}>

## Cancel or Terminate a Workflow

Cancel a Workflow Execution. Cancellation allows cleanup logic to run before the Workflow completes.

Terminate a Workflow Execution. Termination stops the Workflow immediately with no cleanup.

</SetupStep>

<SetupStep code={
<>
<CodeSnippet language="bash">
temporal cloud login
</CodeSnippet>
<CodeSnippet language="bash">
{`temporal workflow list \\
  --address <namespace>.<account>.tmprl.cloud:7233 \\
  --namespace <namespace>.<account>`}
</CodeSnippet>
</>
}>

## Log in to Temporal Cloud

Log in to Temporal Cloud with `temporal cloud login`. After login, you can run commands against Temporal Cloud by
providing the address and Namespace.

See [Use with Temporal Cloud](/cli/cloud) for all authentication options.

</SetupStep>

<SetupStep code={
<>
<CodeSnippet language="bash">
{`temporal schedule create \\
  --schedule-id my-schedule \\
  --interval 1h \\
  --task-queue my-task-queue \\
  --type MyScheduledWorkflow`}
</CodeSnippet>
<CodeSnippet language="bash">
temporal schedule list
</CodeSnippet>
<CodeSnippet language="bash">
{`temporal schedule toggle \\
  --schedule-id my-schedule \\
  --pause --reason "maintenance"`}
</CodeSnippet>
<CodeSnippet language="bash">
{`temporal schedule toggle \\
  --schedule-id my-schedule \\
  --unpause --reason "maintenance complete"`}
</CodeSnippet>
</>
}>

## Work with Schedules

Create a [Schedule](/schedule) that starts a Workflow on an interval.

List all Schedules.

Pause and unpause a Schedule.

</SetupStep>

<SetupStep code={
<>
<CodeSnippet language="bash">
temporal operator namespace list
</CodeSnippet>
<CodeSnippet language="bash">
temporal operator namespace create --namespace my-namespace
</CodeSnippet>
</>
}>

## Manage Namespaces

List available [Namespaces](/namespaces).

Create a new Namespace.

To manage Namespaces on Temporal Cloud, use the Temporal Cloud extension and
[`temporal cloud namespace`](/cli/command-reference/cloud/namespace) commands.

</SetupStep>

<SetupStep code={
<>
<CodeSnippet language="bash">
temporal workflow list --output json
</CodeSnippet>
<CodeSnippet language="bash">
{`temporal workflow list --output json | jq '.[].type.name'`}
</CodeSnippet>
</>
}>

## Format and filter output

Use `--output json` to get machine-readable output from any command.

Combine with [jq](https://jqlang.github.io/jq/) for filtering.

</SetupStep>
</SetupSteps>

## Next steps

- [Use with Temporal Cloud](/cli/cloud) to connect the CLI to Temporal Cloud.
- [Command reference](/cli#command-reference) for the full set of commands and options.

---

## Use with Temporal Cloud

The Temporal CLI works with Temporal Cloud. The same commands you use for local or self-hosted Temporal services, such
as `temporal workflow start` and `temporal workflow list`, work with Temporal Cloud as allowed by your role once you
provide an address and credentials.

For administrative tasks, [install the Temporal Cloud extension](/cli/setup-cli#install-the-temporal-cloud-extension). The extension adds `temporal cloud` commands for
managing your Temporal Cloud account, including Namespaces, users, API keys, and Nexus endpoints.

<ReleaseNoteHeader featureName="cloudCli" />

Access to Temporal Cloud is governed by role-based access control (RBAC). Your ability to perform actions, including
running CLI commands against in Temporal Cloud is determined by the roles and permissions you have been assigned. Refer
to the [Access control](/cloud/manage-access) page for more details.

## Connect to Temporal Cloud

To connect the CLI to Temporal Cloud, provide the Temporal service address, Namespace name, and credentials. Temporal
Cloud supports three credential types:

- OAuth tokens obtained through the `temporal cloud login` command (requires the [Temporal Cloud extension](/cli/setup-cli#install-the-temporal-cloud-extension))
- API keys
- mTLS certificates

### Interactive login

The `temporal cloud login` command opens a browser to authenticate with Temporal Cloud using OAuth. Provide a profile
name to store credentials in. If no profile is specified, credentials are stored in the `default` profile.

```bash
temporal cloud login --profile prod
```

Complete the interactive login process in your browser. After login, your OAuth token is stored in the specified
configuration profile.

To confirm your login, run the `temporal cloud whoami` command:

```bash
temporal cloud whoami
```

Run commands against Temporal Cloud by specifying the profile, address, and Namespace:

```bash
temporal workflow list --profile prod  \
  --address <address>\
  --namespace <namespace>
```

### Non-interactive login

For AI agents, CI pipelines, scripts, and other non-interactive environments, use API keys or mTLS certificates. Store
credentials in a [configuration profile](/develop/environment-configuration#cli-integration) or set them as
[environment variables](/cli/setup-cli#environment-variables) to avoid passing them on every command.

To pass credentials inline:

```bash
