* This page is part of the open-source Flyte v2 docs.
* Full index: https://www.union.ai/docs/v2/flyte/llms.txt
* Flyte is the open-source project. Union.ai is a commercial superset of it and uses the same `flyte` SDK and CLI, so the Union.ai docs cover everything here and more.
* If a question is not answered in these docs, or is about a feature that may be commercial, check the Union.ai v2 docs at https://www.union.ai/docs/v2/union/llms.txt
* These are the v2 docs. v1 is out of date and deprecated. Only refer to v1 docs if asked explicitly about v1. The v1 index is at https://www.union.ai/docs/v1/flyte/llms.txt

What's new in Flyte 2 (pure Python execution, simplified API, fine-grained reproducibility) and how to port a Flyte 1 codebase.

# From Flyte 1 to 2

Flyte 2 represents a fundamental shift in how Flyte workflows are written and executed.

## Pure Python execution

Write workflows in pure Python, enabling a more natural development experience and removing the constraints of a
domain-specific language (DSL).

### Sync Python

```
import flyte

env = flyte.TaskEnvironment("sync_example_env")

@env.task
def hello_world(name: str) -> str:
    return f"Hello, {name}!"

@env.task
def main(name: str) -> str:
    for i in range(10):
        hello_world(name)
    return "Done"

if __name__ == "__main__":
    flyte.init_from_config()
    r = flyte.run(main, name="World")
    print(r.name)
    print(r.url)
    r.wait()
```

*Source: https://github.com/unionai/unionai-examples/blob/main/v2/user-guide/flyte-2/sync_example.py*

### Async Python

```
import asyncio
import flyte

env = flyte.TaskEnvironment("async_example_env")

@env.task
async def hello_world(name: str) -> str:
    return f"Hello, {name}!"

@env.task
async def main(name: str) -> str:
    results = []
    for i in range(10):
        results.append(hello_world(name))
    await asyncio.gather(*results)
    return "Done"

if __name__ == "__main__":
    flyte.init_from_config()
    r = flyte.run(main, name="World")
    print(r.name)
    print(r.url)
    r.wait()
```

*Source: https://github.com/unionai/unionai-examples/blob/main/v2/user-guide/flyte-2/async_example.py*

As you can see in the hello world example, workflows can be constructed at runtime, allowing for more flexible and
adaptive behavior. Flyte 2 supports:

- Python's asynchronous programming model to express parallelism.
- Python's native error handling with `try-except` to overridden configurations, like resource requests.
- Python's native conditional `if`/`elif`/`else` syntax and `for`/`while` loops.

## Simplified API

The new API is more intuitive, with fewer abstractions to learn and a focus on simplicity.

| Use case                      | Flyte 1                     | Flyte 2                                 |
| ----------------------------- | --------------------------- | --------------------------------------- |
| Environment management        | `N/A`                       | `TaskEnvironment`                       |
| Perform basic computation     | `@task`                     | `@env.task`                             |
| Combine tasks into a workflow | `@workflow`                 | `@env.task`                             |
| Create dynamic workflows      | `@dynamic`                  | `@env.task`                             |
| Fanout parallelism            | `flytekit.map`              | Python `for` loop with `asyncio.gather` |
| Conditional execution         | `flytekit.conditional`      | Python `if-elif-else`                   |
| Catching workflow failures    | `@workflow(on_failure=...)` | Python `try-except`                     |

There is no `@workflow` decorator. Instead, "workflows" are authored through a pattern of tasks calling tasks.
Tasks are defined within environments, which encapsulate the context and resources needed for execution.

## Fine-grained reproducibility and recoverability

As in Flyte 1, Flyte 2 supports caching at the task level (via `@env.task(cache=...)`), but it further enables recovery at the finer-grained, sub-task level through a feature called tracing (via `@flyte.trace`).

```
import flyte

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

@flyte.trace
async def call_llm(prompt: str) -> str:
    return "Initial response from LLM"

@env.task
async def finalize_output(output: str) -> str:
    return "Finalized output"

@env.task(cache=flyte.Cache(behavior="auto"))
async def main(prompt: str) -> str:
    output = await call_llm(prompt)
    output = await finalize_output(output)
    return output

if __name__ == "__main__":
    flyte.init_from_config()
    r = flyte.run(main, prompt="Prompt to LLM")
    print(r.name)
    print(r.url)
    r.wait()
```

*Source: https://github.com/unionai/unionai-examples/blob/main/v2/user-guide/flyte-2/trace.py*

Here `call_llm` runs in the same container as `main` and acts as an automated checkpoint with full observability in the UI.
If the task fails due to a system error (e.g., node preemption or infrastructure failure), Flyte can recover and replay from the
last successful trace rather than restarting from the beginning.

Note that tracing is distinct from caching: traces are recovered only if there is a system failure
whereas with cached outputs are persisted for reuse across separate runs.

## Improved remote functionality

Flyte 2 provides full management of the workflow lifecycle through a standardized API through the CLI and the Python SDK.

| Use case      | CLI                | Python SDK          |
| ------------- | ------------------ | ------------------- |
| Run a task    | `flyte run ...`    | `flyte.run(...)`    |
| Deploy a task | `flyte deploy ...` | `flyte.deploy(...)` |

You can also fetch and run remote (previously deployed) tasks within the course of a running workflow.

```
import flyte
from flyte import remote

env_1 = flyte.TaskEnvironment(name="env_1")
env_2 = flyte.TaskEnvironment(name="env_2")
env_1.add_dependency(env_2)

@env_2.task
async def remote_task(x: str) -> str:
    return "Remote task processed: " + x

@env_1.task
async def main() -> str:
    remote_task_ref = remote.Task.get("env_2.remote_task", auto_version="latest")
    r = await remote_task_ref(x="Hello")
    return "main called remote and recieved: " + r

if __name__ == "__main__":
    flyte.init_from_config()
    d = flyte.deploy(env_1)
    print(d[0].summary_repr())
    r = flyte.run(main)
    print(r.name)
    print(r.url)
    r.wait()
```

*Source: https://github.com/unionai/unionai-examples/blob/main/v2/user-guide/flyte-2/remote.py*

## Native notebook support

Author and run workflows and fetch workflow metadata (I/O and logs) directly from Jupyter notebooks.

![Native Notebook](https://www.union.ai/docs/v2/flyte/_static/images/user-guide/notebook.png)

{{< subpage-cards >}}

## Subpages

- [Migration Overview](https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/overview.md) - The Flyte 1 workload patterns you know, and their Flyte 2 equivalents.
  - Pure Python execution
  - Flyte 1
  - Flyte 2
  - Asynchronous model
  - True parallelism for all workloads
  - Calling sync tasks from async tasks
  - The `flyte.map` function: Familiar patterns
  - Sync Map
  - Async Map
  - Terminology and concept mapping
  - Package imports
  - Flyte 1
  - Flyte 2
  - The two mechanical changes behind (almost) every migration
  - 1. Move task configuration into a `TaskEnvironment`
  - 2. Replace `@task` / `@workflow` / `@dynamic` with `@env.task`
  - In this section
  - Quick reference
- [Tasks and workflows](https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/tasks-and-workflows.md) - task, workflow, and dynamic collapse into one decorator, because everything is a task.
  - Hello world: tasks and workflows
  - Flyte 1
  - Flyte 2
  - Chaining and ordering
  - Flyte 1
  - Flyte 2
  - Subworkflows
  - Flyte 1
  - Flyte 2
  - TaskEnvironment configuration
  - Parameter mapping: `@task` → `TaskEnvironment` + `@env.task`
  - Next
- [Task configuration](https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/configuration.md) - Image, resources, caching, secrets, and scheduling move from the task decorator to the environment.
  - Image, resources, and caching
  - Flyte 1
  - Flyte 2
  - Container images
  - Resources
  - Caching
  - Secrets
  - Flyte 1
  - Flyte 2
  - Scheduling
  - Flyte 1
  - Flyte 2
  - Next
- [CLI and configuration](https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/cli-and-configuration.md) - pyflyte becomes flyte, and the config file gets much smaller.
  - CLI command mapping
  - Running tasks
  - Flyte 1
  - Flyte 2
  - Deploying
  - Flyte 1
  - Flyte 2
  - Key flag differences
  - Configuration files
  - Flyte 1
  - Flyte 2
  - Configuring in code
  - Next
- [Control flow](https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/control-flow.md) - Branching, fan-out, and failure handling become ordinary Python instead of DSL constructs.
  - Conditional execution
  - Flyte 1
  - Flyte 2
  - Dynamic workflows
  - Flyte 1
  - Flyte 2
  - Error handling
  - Flyte 1
  - Flyte 2
  - Next
- [Parallelism and fan-out](https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/parallelism.md) - map_task becomes flyte.map, and fan-out becomes async and asyncio.gather.
  - Fan-out: `map_task`
  - Flyte 1
  - Flyte 2 (flyte.map)
  - Flyte 2 (asyncio.gather)
  - Choosing `flyte.map` vs `asyncio.gather`
  - Concurrency control and error handling
  - Data backfills
  - Flyte 1
  - Flyte 2
  - Next
- [Data types and I/O](https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/data-io.md) - The offloaded-data types are renamed and their I/O is async, but the mental model is unchanged.
  - Files and directories
  - Flyte 1
  - Flyte 2
  - DataFrames
  - Flyte 1
  - Flyte 2
  - Dataclasses and structured types
  - Flyte 1
  - Flyte 2
  - Data ETL
  - Flyte 1
  - Flyte 2
  - Next
- [ML workloads](https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/ml-workloads.md) - Everyday ML workloads as complete Flyte 1 to Flyte 2 pairs.
  - Small model training (scikit-learn / XGBoost)
  - Flyte 1
  - Flyte 2
  - Hyperparameter optimization
  - Flyte 1
  - Flyte 2
  - Large model training (deep learning)
  - Flyte 1
  - Flyte 2
  - Batch inference
  - Flyte 1
  - Flyte 2
  - A complete example: end-to-end ML pipeline
  - Flyte 1
  - Flyte 2
  - Next
- [New in Flyte 2](https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/new-in-flyte-2.md) - What Flyte 2 adds on top of batch orchestration, starting with long-running services.
  - Real-time inference and model serving
  - LLM serving
  - App serving (dashboards and APIs)
  - Dynamic batching for GPU inference
  - Sandboxed code execution
  - Next
- [Hybrid v1 and v2 pipelines](https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/hybrid-pipelines.md) - Run Flyte 1 and Flyte 2 workloads side by side and have them call each other.
  - Running a Flyte 2 task from a Flyte 1 workflow
  - 1. Create the API key and store it
  - 2. Write the bridging task
  - Running a Flyte 1 workflow from a Flyte 2 task
  - Considerations
  - See also
- [Gotchas and caveats](https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/gotchas-and-caveats.md) - Where Flyte 2's flexibility can surprise you, and what to watch for.
  - Common gotchas
  - Non-deterministic behavior
  - Dealing with non-determinism
  - Type safety
  - No global state
  - Driver pod requirements
  - OOM risk from materialized I/O

---
**Source**: https://github.com/unionai/unionai-docs/blob/main/content/user-guide/migration/flyte-2/_index.md
**HTML**: https://www.union.ai/docs/v2/flyte/user-guide/migration/flyte-2/
