> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lazycloud.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Images

> Build a workload's container from Python: packages, system tools, a project's lockfile, or an existing registry image.

Anything a workload needs beyond the standard library goes in its `Image`,
along with the Python version it runs. LazyCloud builds the image in the cloud,
so nothing installs on your machine.

## Install remote dependencies

```python theme={null}
from lazycloud import App, Image

app = App("audio")

image = (
    Image(python_version="3.12")
    .add_commands(["apt-get update && apt-get install -y ffmpeg"])
)


@app.function(image=image)
def ffmpeg_version() -> str:
    import subprocess

    return subprocess.check_output(["ffmpeg", "-version"], text=True).splitlines()[0]
```

`uv run lazycloud run audio:ffmpeg_version` prints the ffmpeg version from the
cloud container, and your machine never needs ffmpeg.
`.add_python_packages(["httpx"])` adds a Python package.

`Image()` alone is the managed Python 3.12 image, and Python 3.10 through 3.14,
or a patch release such as `3.12.11`, are available. Images are cached by
content, so an unchanged image never rebuilds.

## Create an image from a project

A factory builds from the project's own dependency files:

```python theme={null}
from lazycloud import Image

image = Image.from_uv(".")
```

The build reads the directory's `pyproject.toml`, lockfile, and
`.python-version`, plus any local path dependencies inside it. It installs
dependencies only. Your own code reaches the container through source sync, so
editing it never rebuilds the image, and code under `src/` still imports.

### uv

```python theme={null}
image = Image.from_uv(".", extras=["gpu"], groups=["inference"])
```

Needs `pyproject.toml` and `uv.lock`, and installs exactly what's locked.
Dependency groups, including `dev`, install only when `groups` names them.

### Poetry

```python theme={null}
image = Image.from_poetry(".", extras=["gpu"], groups=["inference"])
```

Needs `pyproject.toml` and `poetry.lock`, and installs the locked main
dependencies plus the selected groups and extras.

### Standard pyproject.toml

```python theme={null}
image = Image.from_pyproject(".", extras=["gpu"], groups=["inference"])
```

Reads standard `[project]` metadata and `[dependency-groups]` and resolves
versions at build time, with no lockfile. `from_uv` and `from_poetry` are the
locked options.

### Micromamba

```yaml environment.yml theme={null}
channels:
  - conda-forge
dependencies:
  - python=3.12
  - numpy
  - pip:
      - httpx==0.28.1
```

```python theme={null}
image = Image.from_micromamba("environment.yml")
```

The environment file supplies Python, channels, Conda packages, and pip
dependencies. Unpinned packages resolve at build time.

### Python selection

An explicit `python_version` overrides the project's interpreter pin:

```python theme={null}
image = Image.from_uv(".", python_version="3.12.11")
```

Otherwise the project's `.python-version`, or Micromamba's `python=` entry,
decides, with 3.12 as the fallback. An unsupported pin fails.

Factories return an ordinary image that extends like any other:

```python theme={null}
image = Image.from_uv(".").add_commands([
    "apt-get update && apt-get install -y ffmpeg"
])
```

All four also accept `base_image`, `base_image_creds`, and `architecture`:

```python theme={null}
image = Image.from_uv(
    ".", base_image="nvidia/cuda:12.3.1-runtime-ubuntu22.04"
)
```

The CLI still imports your module locally, so top-level imports need to resolve
on your machine. Remote-only packages can be imported inside the function.

## Constructor

```python theme={null}
Image(
    python_version="3.12",         # supported minor or exact patch release
    python_packages=["httpx"],     # package specs, or a path to requirements.txt
    commands=["python --version"], # shell commands run during the build
    base_image=None,               # start from a registry image instead
    base_image_creds=None,         # registry credentials, see below
    env_vars=None,                 # environment variables baked into the image
)
```

## Builder methods

Each returns the image, so they chain.

* `add_python_packages(packages)` installs packages. Pass a list of specs or a
  path to a `requirements.txt`.
* `add_commands(commands)` runs shell commands during the build.
* `add_local_path(pattern="*")` includes matching local files in the build
  context.
* `add_micromamba_packages(packages, channels=[...])` adds packages to an image
  created with `from_micromamba()`.
* `with_envs(env_vars, clear=False)` sets environment variables from a
  mapping, `"KEY=value"` strings, or a sequence of them.
* `with_secrets(secrets)` makes workspace secrets available during the build.
* `with_docker()` installs Docker so containers using the image can run their
  own daemon.
* `build_with_gpu(hint)` runs the build on a GPU worker of the given model.

## Start from an existing image

```python theme={null}
gpu_image = Image.from_registry(
    "nvidia/cuda:12.3.1-runtime-ubuntu22.04", python_version="3.11"
)
custom_image = Image.from_dockerfile("./Dockerfile", context_dir=".")
```

`Image.from_id(image_id)` reuses a sandbox filesystem snapshot, given the ID
the snapshot returned.

### Private registries

`credentials` names environment variables that LazyCloud reads on your machine
when the image builds, so values stay out of code:

```python theme={null}
image = Image.from_registry(
    "ghcr.io/acme/models:latest",
    credentials=["GITHUB_USERNAME", "GITHUB_TOKEN"],
)
```

A dict maps the same names to values you've already loaded:
`{"GITHUB_USERNAME": "acme-bot", "GITHUB_TOKEN": os.environ["CI_GHCR_TOKEN"]}`.
A listed variable that isn't set stops the build before it starts. The names
are fixed per registry, and any other name is ignored:

| Registry                       | Names                                                                                       |
| ------------------------------ | ------------------------------------------------------------------------------------------- |
| GitHub, `ghcr.io`              | `GITHUB_USERNAME` and `GITHUB_TOKEN`                                                        |
| Amazon ECR                     | `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, optional `AWS_SESSION_TOKEN` and `AWS_REGION` |
| Google, `gcr.io` and `pkg.dev` | `GCP_ACCESS_TOKEN` or `GOOGLE_APPLICATION_CREDENTIALS`, optional `GCP_PROJECT_ID`           |
| Azure, `azurecr.io`            | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, optional `AZURE_TENANT_ID`                        |
| NVIDIA, `nvcr.io`              | `NGC_API_KEY`                                                                               |
| Docker Hub and others          | `DOCKERHUB_TOKEN`, or `REGISTRY_USERNAME` and `REGISTRY_PASSWORD`                           |

`GOOGLE_APPLICATION_CREDENTIALS` can be a file path or the JSON itself. The
constructor and project factories take the same value as `base_image_creds`.
