# Run locally in Python

Flyte runs locally with no cluster or Docker needed. Install the SDK, write tasks, and run them on your machine. When you're ready to scale, drop the `--local` flag and the same code runs on a remote cluster with GPUs.

## Getting started

If you haven't already, install the SDK and configure local persistence as described in the [Quickstart](https://www.union.ai/docs/v2/union/user-guide/run-modes/quickstart).

## Running tasks locally

The `--local` flag tells Flyte to execute a task in your local Python environment rather than on a remote cluster. Add `--tui` to launch the interactive Terminal UI for real-time monitoring.

Basic local execution:

```bash
flyte run --local hello.py main
```

With the interactive TUI:

```bash
flyte run --local --tui hello.py main
```

You can also run tasks programmatically using the Python SDK with `flyte.run()`. See [Run and deploy tasks](https://www.union.ai/docs/v2/union/user-guide/run-modes/task-deployment/_index) for details.

## Two ways to run a task

There are two distinct ways to run a task, and it's easy to confuse them when you're new. They differ in *who* calls `flyte.run()`.

### As a script: `python hello.py`

You call `flyte.run()` yourself, from inside an `if __name__ == "__main__":` block, and execute the file with plain Python:

```python
# hello.py
import flyte

env = flyte.TaskEnvironment(name="hello_env")

@env.task
def main(x_list: list[int] = list(range(10))) -> float:
    return sum(x_list) / len(x_list)

if __name__ == "__main__":
    flyte.init_from_config()       # load your local config (.flyte/config.yaml)
    run = flyte.run(main)          # call the task; pass inputs as keyword args
    print(run.name)
    run.wait()
```

Then run the file as an ordinary Python script:

```bash
python hello.py
```

Because *your code* decides which task runs and with what inputs, you pass inputs directly as arguments to `flyte.run()` — for example `flyte.run(main, x_list=[1, 2, 3])`. Use `flyte.run.aio(...)` from within async code.

### Via the CLI: `flyte run`

The `flyte run` CLI does the calling for you. You don't need a `__main__` block — instead you name the file and the task on the command line, and the CLI invokes it:

```bash
flyte run --local hello.py main
```

The task's **parameters become CLI options**. Each task input maps to a `--<name>` flag (run `flyte run --local hello.py main --help` to see them, with their defaults). For example, to override `x_list`:

```bash
flyte run --local hello.py main --x-list '[1, 2, 3]'
```

> [!NOTE]
> A common first-run trip-up: invoking `flyte run` against a task whose inputs have **no defaults** without supplying them. The CLI then can't construct the input and you'll see a confusing type-converter error rather than a "missing argument" message. If you hit one, check `--help` and pass the required `--<name>` values (or give the parameters defaults in the task signature, as `main` does above).

## Terminal UI

The TUI is an interactive split-screen dashboard. Task tree on the left, details and logs on the right.

```bash
flyte run --local hello.py main
```

![TUI agent run](https://www.union.ai/docs/v2/union/user-guide/_static/images/user-guide/quickstart/run-tui.png)

What you see:

- **Task tree** with live status: `●` running, `✓` done, `✗` failed
- **Cache indicators**: `$` cache hit, `~` cache enabled but missed
- **Live logs**: `print()` output streams in real time
- **Details panel**: inputs, outputs, timing, report paths
- **Traced sub-tasks**: child nodes for `@flyte.trace` decorated functions

**Keyboard shortcuts:**

| Key | Action |
|-----|--------|
| `q` | Quit |
| `d` | Details tab |
| `l` | Logs tab |

### Exploring past runs

If you created a config file via `flyte create config --local-persistence`, Flyte
persists the inputs and outputs of every task run locally, so you can always go back and inspect what a task received and produced. Launch the TUI on its own to browse past runs, compare inputs and outputs, and review reports:

```bash
flyte start tui
```

---

## What works locally

Most Flyte features work in both local and remote execution. The table below summarizes how each feature behaves locally.

| Feature | Local behavior | Details |
|---------|---------------|---------|
| **Caching** | Outputs stored in local SQLite, keyed on task name and inputs. Same inputs = instant results. | [Caching](https://www.union.ai/docs/v2/union/user-guide/run-modes/task-configuration/caching) |
| **Tracing** | `@flyte.trace` functions appear as child nodes in the TUI with their own timing, inputs, and outputs. | [Traces](https://www.union.ai/docs/v2/union/user-guide/run-modes/task-programming/traces) |
| **Reports** | HTML files saved locally. TUI shows the file path. | [Reports](https://www.union.ai/docs/v2/union/user-guide/run-modes/task-programming/reports) |
| **Serving** | Run apps locally with `python serve.py` or `flyte.with_servecontext(mode="local")`. | [Serve and deploy apps](https://www.union.ai/docs/v2/union/user-guide/run-modes/serve-and-deploy-apps/_index) |
| **Plugins** | Same decorators and APIs as remote. Secrets come from environment variables. | [Integrations](https://www.union.ai/docs/v2/union/user-guide/api-reference/integrations/_index) |
| **Secrets** | Read from `.env` files or environment variables. No `flyte create secret` needed. | [Secrets](https://www.union.ai/docs/v2/union/user-guide/run-modes/task-configuration/secrets) |

---

## Local to devbox/remote

The same code runs in both environments. Here's what changes:

| Aspect | Local | Devbox/Remote |
|--------|-------|--------|
| **Run pipeline** | `flyte run --local` | `flyte run` |
| **TUI** | `--tui` flag | Dashboard in Flyte UI |
| **Caching** | Local SQLite | Cluster-wide distributed cache |
| **Reports** | Local HTML files | Rendered in the Flyte UI |
| **Serving** | `python serve.py` | `flyte deploy serve.py env` |
| **Secrets** | `.env` / environment variables | `flyte create secret` / `flyte.Secret` |
| **Compute** | Your CPU/GPU | `Resources(cpu=2, memory="4Gi", gpu=1)` |

The [`TaskEnvironment`](https://www.union.ai/docs/v2/union/user-guide/run-modes/core-concepts/task-environment) is the bridge. Locally, image and resource settings are ignored. On the cluster, Flyte builds containers and allocates compute from the same definition.

---

## Next steps

- [**Run on the devbox**](https://www.union.ai/docs/v2/union/user-guide/run-modes/running-locally/running-devbox): Run a full local Flyte cluster with Docker to test containerized execution before deploying remotely.
- [**Run on a remote cluster**](https://www.union.ai/docs/v2/union/user-guide/run-modes/running-locally/running-remote): Configure the CLI and SDK to run on a remote Flyte cluster.

---
**Source**: https://github.com/unionai/unionai-docs/blob/main/content/user-guide/run-modes/running-locally.md
**HTML**: https://www.union.ai/docs/v2/union/user-guide/run-modes/running-locally/
