Hybrid v1 and v2 pipelines
Migrations rarely happen all at once. For a while you’ll have Flyte 1 and Flyte 2 workloads running side by side, and you’ll want them to call each other: a Flyte 1 workflow that kicks off a newly ported Flyte 2 task, or a Flyte 2 task that triggers a workflow that hasn’t been migrated yet.
You can bridge the two in both directions. The idea is the same each way: one task installs both SDKs, authenticates to the other control plane, fetches the entity it wants to run, and launches it.
Running a Flyte 2 task from a Flyte 1 workflow
The bridge is a single Flyte 1 task — call it launch_v2_from_v1 — that runs the Flyte 2 client.
High-level steps:
- Give the
launch_v2_from_v1task an image with bothflytekit(Flyte 1) andflyte(Flyte 2) installed. - Give it a Flyte 2 API key (see
Create the API key below — how you create one differs between Union and open-source Flyte). The key is the
export FLYTE_API_KEY="..."value it produces. - Make the key available to the task, either by storing it as a secret it can read, or by injecting it as the
FLYTE_API_KEYenvironment variable. - Authenticate inside the task with
flyte.init_from_api_key(). - Fetch the deployed Flyte 2 task with
flyte.remote.Task.get(...)and run it withflyte.run(...).
1. Create the API key and store it
Create a key with flyte create api-key (a command provided by the flyteplugins-union plugin) or through the Union UI, then store it as a secret:
# Create a Flyte 2 API key (prints `export FLYTE_API_KEY="..."`)
flyte create api-key --name v1-to-v2-bridge
# Store that value as a Flyte 2 secret (you can also create it in the Union UI)
flyte create secret flyte_api_key --value "<the-encoded-key>"You can also make the same value available to your Flyte 1 task as a secret through your existing Flyte 1 secret workflow, or set it directly as the FLYTE_API_KEY environment variable on the task.
2. Write the bridging task
import flytekit
from flytekit import task, workflow, ImageSpec, Secret, current_context
# The bridge image needs BOTH the v1 (flytekit) and v2 (flyte) SDKs.
bridge_image = ImageSpec(
name="v1-to-v2-bridge",
packages=["flytekit", "flyte"],
)
@task(
container_image=bridge_image,
secret_requests=[Secret(group="flyte", key="flyte_api_key")],
)
def launch_v2_from_v1(x: int) -> str:
import flyte
import flyte.remote
# Authenticate to the Flyte 2 control plane with the API key.
# Option A: read the mounted secret and pass it explicitly.
api_key = current_context().secrets.get(group="flyte", key="flyte_api_key")
flyte.init_from_api_key(api_key=api_key)
# Option B: if FLYTE_API_KEY is set as an env var, no argument is needed:
# flyte.init_from_api_key()
# Fetch the deployed Flyte 2 task and run it.
remote_v2_task = flyte.remote.Task.get(
"my_v2_env.process",
auto_version="latest",
)
run = flyte.run(remote_v2_task, x=x)
run.wait() # optional: block until the v2 run finishes
return run.url
@workflow
def main(x: int) -> str:
return launch_v2_from_v1(x=x)The referenced Flyte 2 task (my_v2_env.process above) must be deployed before the bridge runs — flyte.remote.Task.get() looks it up by env_name.task_name. See
Remote tasks for versioning options (auto_version="latest", version="v1.2.3") and flyte.run details.
flyte.init_from_api_key() is required here — do not use flyte.init_from_config(), which reads a config.yaml that has no API-key field. See
Run on a remote cluster for the authentication methods.Running a Flyte 1 workflow from a Flyte 2 task
The reverse works the same way: a Flyte 2 task installs the Flyte 1 client and uses UnionRemote to launch a Flyte 1 workflow.
High-level steps:
- Give the
launch_v1_from_v2TaskEnvironmentan image with the Flyte 1 client (union) installed. - Provide the task with credentials for the Flyte 1 control plane (a config file or API key, supplied as a secret).
- Instantiate a
UnionRemoteclient inside the task. - Fetch the Flyte 1 workflow with
fetch_workflow(...). - Launch it with
execute(...).
import flyte
env = flyte.TaskEnvironment(
name="v2_to_v1_bridge",
# The image needs the Flyte 1 client installed.
image=flyte.Image.from_debian_base().with_pip_packages("union"),
# Supply credentials for the Flyte 1 control plane (config or API key).
secrets=[flyte.Secret(key="v1_client_secret", as_env_var="V1_CLIENT_SECRET")],
)
@env.task
async def launch_v1_from_v2(x: int) -> str:
from flytekit.remote import FlyteRemote
from flytekit.configuration import Config
# Point the client at your Flyte 1 cluster.
remote = FlyteRemote(
config=Config.for_endpoint(endpoint="my-v1-cluster.example.com"),
default_project="flytesnacks",
default_domain="development",
)
# Fetch the deployed Flyte 1 workflow and execute it.
wf = remote.fetch_workflow(name="my_v1_module.main", version="v1.2.3")
execution = remote.execute(wf, inputs={"x": x}, wait=True)
return execution.id.nameOn Union, use union.remote.UnionRemote instead of flytekit.remote.FlyteRemote. It auto-detects your Union configuration, so you can construct it with no arguments:
from union.remote import UnionRemote
remote = UnionRemote(default_project="flytesnacks", default_domain="development")
wf = remote.fetch_workflow(name="my_v1_module.main", version="v1.2.3")
execution = remote.execute(wf, inputs={"x": x}, wait=True)Considerations
- Both SDKs in one image. The bridging task installs
flytekitandflytetogether. Pin versions and watch for dependency conflicts; keep the bridge image minimal. - Deploy the callee first. For the v1→v2 direction, the Flyte 2 task must be deployed (
flyte deploy) beforeflyte.remote.Task.get()can resolve it. For the v2→v1 direction, the Flyte 1 workflow must be registered on its cluster. - Wait vs. fire-and-forget. Both
run.wait()(v2) andexecute(..., wait=True)(v1) block until the launched run finishes. Omit them to launch and return immediately, then poll or hand off the execution URL. - Credentials cross a boundary. The bridge authenticates to a different control plane than the one it runs on. Store the API key or client credentials as a secret — never hard-code them. See Secrets and Run on a remote cluster.
- Keep the bridge lightweight. Like any orchestrating task, it should mostly launch and assemble results rather than do heavy compute — see Gotchas and caveats.
See also
- Remote tasks — fetching and running deployed Flyte 2 tasks
-
Run on a remote cluster — authentication methods, including
flyte.init_from_api_key()- Authenticating — API key authentication in depth
- Migration — mapping Flyte 1 workload patterns to Flyte 2