Code artifacts#
A code artifact (kind="code") stores a function or workflow source file (or an archive of files) as a versioned MLRun artifact. Once logged, the artifact can be referenced by a store:// URI as the source for set_function() or set_workflow(), in addition to a local path, git source, or remote URL. The code is downloaded by the runner pod at runtime — the client never resolves the URI.
In this section
See also
Log a code artifact#
Use log_code_file() to register a Python file or archive as a code artifact:
# Minimal — local file uploaded to the project's artifact path
artifact = project.log_code_file("my_func_code", local_path="./my_func.py")
Common variants:
# Upload to a specific remote target
project.log_code_file(
"my_func_code",
local_path="./my_func.py",
target_path="s3://bucket/funcs/my_func.py",
)
# Reference an existing object via a datastore profile (recommended when
# credentials should be centralized server-side)
project.log_code_file(
"my_func_code",
target_path="ds://my-profile/funcs/my_func.py",
)
# Inline body (small files only)
project.log_code_file("my_func_code", body=b"def main():\n return 'ok'\n")
# Archive containing multiple source files; extracted on resolution
project.log_code_file("my_pkg_code", local_path="./my_pkg.zip")
# With an explicit code_type and pip dependencies
project.log_code_file(
"my_workflow_code",
local_path="./my_workflow.py",
code_type="workflow",
requirements=["pandas>=2.0"],
)
language is auto-derived from the file suffix when omitted (.py / .ipynb → "python"). code_type defaults to "function". See function vs workflow code_type and Requirements and rebuild behavior for those parameters.
Run a function from a code artifact#
Pass the artifact's store:// URI as the func argument:
fn = project.set_function(
func="store://artifacts/my-project/my_func_code",
name="my_func",
kind="job",
handler="my_func:main",
)
fn.run(params={"p1": 5})
The store:// URI is stored as-is in the function and in the MLRun DB. The runner pod resolves the artifact and downloads the code at startup ("pull at runtime").
For Nuclio and serving functions, the default is "pull at buildtime" mode: the server downloads the code at deploy and embeds it in the processor image. Set load_source_on_run=True on the function spec to switch to "pull at runtime" mode, where an init container fetches the code at pod startup (no image rebuild on code-only changes). See function storage for the general source-loading mechanism.
When running locally (fn.run(local=True)), the client resolves the artifact and must have datastore credentials configured.
Handler format#
When the source is a store:// code artifact, the handler argument must be in "<module>:<function>" form:
artifact = project.log_code_file("my_func_code", local_path="./my_func.py")
fn = project.set_function(
func=artifact.uri,
name="my_func",
kind="job",
handler="my_func:main", # <module>:<function>
)
fn.run()
The module segment is the file's basename without the .py extension. The colon form is required because the runner downloads the artifact at startup — there is no local spec.command pointing at a file, so the handler itself must identify which extracted module to load.
When the artifact is an archive (.zip / .tar.gz), the module segment refers to a file inside the extracted archive, not to the archive itself. For example, if my_pkg.zip extracts to trainer.py and utils.py, the handler is "trainer:main" — not "my_pkg:main":
artifact = project.log_code_file("my_pkg_code", local_path="./my_pkg.zip")
fn = project.set_function(
func=artifact.uri,
name="trainer",
kind="job",
handler="trainer:main", # file inside the archive, not "my_pkg"
)
Run a workflow from a code artifact#
set_workflow accepts a store:// URI as workflow_path:
project.set_workflow(
name="main",
workflow_path="store://artifacts/my-project/my_workflow_code",
)
project.run(name="main", arguments={"p1": 5})
The workflow file is downloaded by the runner pod at execution time. Supported engines: kfp, remote, remote:kfp, remote:local, local.
Requirements and rebuild behavior#
A code artifact can declare its own pip dependencies:
project.log_code_file(
"my_func_code",
local_path="./my_func.py",
requirements=["pandas>=2.0", "numpy"],
)
At deploy or run time the server merges the artifact's requirements into function.spec.build.requirements. User-set requirements (via func.with_requirements()) take priority over artifact requirements, and deduplication is case-insensitive.
A change to the artifact's requirements is a build-configuration change, and like any other such change it is not detected automatically (auto_build does not pick it up). Rebuild the image as described in Build function image.
A change to the code only (no requirements change) depends on the source-loading mode described in Run a function from a code artifact. When the code is resolved at build time it is embedded in the image, so a code change is also a build-configuration change and the image must be rebuilt. When the code is resolved at runtime it is fetched by the pod at startup, so a code change is not a build-configuration change and no rebuild is needed. For job and KFP functions the next run() picks up the latest artifact version.
function vs workflow code_type#
Code artifacts carry a code_type field whose value ("function" or "workflow") tells consumers what the artifact is intended for. Using an artifact in the wrong role raises MLRunInvalidArgumentError at the set_function / set_workflow call (and again on the server at deploy time):
project.log_code_file(
"my_workflow_code",
local_path="./my_workflow.py",
code_type="workflow",
)
# This raises MLRunInvalidArgumentError because the artifact is a workflow:
project.set_function(
func="store://artifacts/my-project/my_workflow_code",
name="bad",
kind="job",
handler="my_workflow:main",
)
Project export behavior#
project.export() behaves differently depending on whether code artifacts are referenced:
Zip export — the code is retrieved from each referenced artifact and packaged into the zip. On import the function references a local file path inside the unpacked project, so the project is portable across clusters.
YAML-only export (
project.yaml) — thestore://URI is preserved as-is. The project is only usable on a cluster that already has the same artifact.