Skip to content

Build an image from source code

プレミアム機能

Workload APIはプレミアム機能です。 この機能を有効にする方法については、DataRobotの担当者または管理者にお問い合わせください。

Most artifacts reference a container image you already built and pushed (imageUri). The alternative is to hand DataRobot your source code and let the platform build the image for you—no local docker build, no registry push, no credentials to manage. This is often called code to Workload.

Set imageBuildConfig on a container instead of imageUri, point it at your uploaded source with a codeRef, and trigger a build. When the build completes, the platform writes imageUri back onto the container for you.

For triggering builds and tracking their status, see Trigger and manage builds. For a worked example, see Tutorial: Build a Workload from source.

Source-to-image flow

The following diagram traces a build from your uploaded source to a running Workload.

flowchart LR
    S["<b>Source directory</b><br/><i>your project</i>"] --> C["<b>Catalog version</b><br/><i>uploaded snapshot</i>"]
    C --> R["<b>codeRef</b><br/><i>pointer on the artifact</i>"]
    R --> B["<b>Build</b><br/><i>image built and pushed</i>"]
    B --> I["<b>imageUri</b><br/><i>written to the container</i>"]
    I --> W["<b>Workload</b><br/><i>running endpoint</i>"] 

Each step is separately addressable: re-upload source without rebuilding, rebuild without redeploying, or deploy the same built image to more than one Workload.

This process requires a draft artifact of type service, agent, or mcp. Builds run only against draft artifacts of those types; locked artifacts are immutable, and other artifact types cannot use imageBuildConfig—a nim artifact, for example, always references a pre-built NVIDIA container image and is never eligible for a source build.

Select the source code with codeRef

A codeRef identifies a specific version of your source code that has already been uploaded to DataRobot. It is a pointer into the DataRobot catalog, produced when you upload a snapshot of your project directory.

A codeRef is not a Git reference

Despite the name, codeRef does not point at a repository. There is no URL, branch, tag, or commit to select—see What codeRef does not support. The unit of selection is an uploaded catalog version, and you choose which version by choosing its ID.

Location within imageBuildConfig

codeRef is a field on the container, nested under imageBuildConfig:

spec.containerGroups[].containers[].imageBuildConfig.codeRef 

codeRef fields

A codeRef has the following shape:

"codeRef": {
  "type": "datarobot",
  "provider": "datarobot",
  "datarobot": {
    "catalogId": "68f0c1a2b3d4e5f607182930",
    "catalogVersionId": "68f0c1a2b3d4e5f607182931"
  }
} 

The following table describes each field.

フィールド タイプ 必須 説明
type "datarobot" いいえ Source kind. datarobot is the only accepted value; it defaults to datarobot when omitted.
provider "datarobot" いいえ Source provider. datarobot is the only accepted value; it defaults to datarobot when omitted.
datarobot object はい The catalog coordinates.
datarobot.catalogId 文字列 はい The catalog item holding your source code. Must be a 24-character hexadecimal ID.
datarobot.catalogVersionId 文字列 はい The specific version of that catalog item to build. Must be a 24-character hexadecimal ID.

Because catalogId and catalogVersionId are used to construct DataRobot API paths, both are validated strictly. Surrounding whitespace is trimmed, and the following errors are returned for malformed values:

エラー 原因
catalog_id and catalog_version_id must be non-empty when code_ref is set One of the two IDs is missing or blank.
catalog_id and catalog_version_id must be 24-character hexadecimal identifiers One of the two IDs is not a 24-character hex string.

Both IDs are also checked for existence when you create or update the artifact: the platform reads the catalog version as you, so a nonexistent ID—or one you cannot access—is rejected at that point rather than at build time.

Upload source and set the codeRef

Upload source and register the resulting codeRef through either interface: the CLI for a project directory already linked via dr artifact code init, or the REST API when scripting the upload directly.

The CLI handles the upload and the codeRef update together. Link the directory once, then sync whenever you change the code:

# Link this project directory to an existing draft artifact
dr artifact code init ${ARTIFACT_ID}

# Upload the current contents and update the artifact's codeRef
dr artifact code sync 

sync creates a new catalog version on every run and repoints the artifact's codeRef at it, so the artifact always references the snapshot you last pushed. Preview what would be uploaded with dr artifact code sync --dry-run. See Manage artifacts with the CLI.

Exclude files from the upload

dr artifact code init drops a starter .drignore at the project root, in gitignore syntax, listing what sync leaves out. Edit it and commit it. An uploaded .venv/ or node_modules/ bloats the catalog version and can interfere with runtime detection for generated Dockerfiles.

Projects linked by an older CLI have a .wapiignore instead. It is still honored when no .drignore sits beside it, but the name is deprecated—rename it when convenient. If both exist, only .drignore applies.

Upload the source, wait for the upload to finish, then patch the artifact.

# 1. Upload a zip of your project
curl -s -X POST "${DATAROBOT_ENDPOINT}/files/fromFile/" \
  -H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
  -F "file=@source.zip" | tee /tmp/upload.json

export CATALOG_ID=$(jq -r '.catalogId' /tmp/upload.json)
export CATALOG_VERSION_ID=$(jq -r '.catalogVersionId' /tmp/upload.json)
export STATUS_ID=$(jq -r '.statusId' /tmp/upload.json) 

The response is 202 with catalogId, catalogVersionId, and a statusId. The upload finishes asynchronously; poll its status by id until it redirects—this endpoint signals completion with a 303, not a status field in a JSON body:

until [ "$(curl -s -o /dev/null -w '%{http_code}' \
  "${DATAROBOT_ENDPOINT}/status/${STATUS_ID}/" \
  -H "Authorization: Bearer ${DATAROBOT_API_TOKEN}")" = "303" ]; do
  sleep 2
done 

Then attach the result to the artifact:

curl -s -X PATCH "${DATAROBOT_ENDPOINT}/artifacts/${ARTIFACT_ID}" \
  -H "Authorization: Bearer ${DATAROBOT_API_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "spec": {
      "containerGroups": [{
        "containers": [{
          "name": "primary",
          "primary": true,
          "port": 8080,
          "imageBuildConfig": {
            "codeRef": {
              "datarobot": {
                "catalogId": "'${CATALOG_ID}'",
                "catalogVersionId": "'${CATALOG_VERSION_ID}'"
              }
            }
          }
        }]
      }]
    }
  }' 

Update the source on an existing artifact

Point the codeRef at a newer catalogVersionId and trigger a new build. Two behaviors are worth knowing:

  • The previous imageUri is retained. Changing the codeRef does not clear the image the artifact already has, so the last successfully built image stays deployable until a new build completes. It is stale, not gone.
  • The build pointer is cleared. The build block on the container is dropped when the codeRef changes, because the recorded build no longer describes the current source.

Resend the whole container, not just codeRef

A PATCH that names a container replaces that container's full definition—it does not merge in only the fields you send. Patching imageBuildConfig.codeRef alone drops any sibling fields the request omits, silently resetting dockerfile to its provided/./Dockerfile default and clearing fields like readinessProbe. Always resend the container's complete current definition, with only codeRef changed.

imageUri is managed by the platform

On a container that uses imageBuildConfig, you cannot set imageUri yourself. Sending a different value returns 422: Container '<name>': imageUri cannot be set on a container with imageBuildConfig; it is populated by the platform when the image build completes. Echoing back the value the platform already stored—as happens in a read-modify-write round trip—is accepted.

What codeRef does not support

The following capabilities are common in build systems but are not supported by codeRef; each has a documented workaround.

サポートされていません What to do instead
Git repository URLs, branches, tags, or commits Upload a snapshot of your working tree. Use your own CI to sync a checkout if you need Git as the source of truth.
Credentials for private repositories Not applicable—access is governed by your DataRobot API token and your permissions on the catalog item.
Container registry references as a build source Use imageUri to reference a pre-built image directly.
Selecting a subdirectory of the upload as the build context The build context is always the root of the catalog version. To build from a Dockerfile in a subdirectory, set dockerfile.path—but the context stays at the root.
More than one container building from source Only one container per artifact may define imageBuildConfig. Supply imageUri for sidecars.

Choose how the Dockerfile is obtained

imageBuildConfig.dockerfile is a discriminated union on the source field. Pick provided when you want full control of the image, and generated when you would rather not write a Dockerfile at all.

フィールド タイプ デフォルト 説明
codeRef object or null null Source code to build. Optional at create time; required before you build or lock.
dockerfile ProvidedDockerfile or GeneratedDockerfile {"source": "provided", "path": "./Dockerfile"} How the Dockerfile is obtained.

Option 1: Use a provided Dockerfile

Set dockerfile.source to provided to build from a Dockerfile that's already part of your uploaded source:

"imageBuildConfig": {
  "dockerfile": {
    "source": "provided",
    "path": "./Dockerfile"
  }
} 
フィールド タイプ デフォルト 説明
source "provided" "provided" Selects this variant.
path 文字列 "./Dockerfile" Path to the Dockerfile, relative to the root of the uploaded source. Maximum 2048 characters.

The path is normalized before lookup, so ./docker/Dockerfile.prod and docker/Dockerfile.prod are equivalent. Matching is on the full relative path, not the filename, so a Dockerfile in a subdirectory is found only if path names that subdirectory.

The build context is always the upload root

Setting path to services/api/Dockerfile selects that Dockerfile, but the build context remains the root of the catalog version. Write COPY instructions relative to the root, for example COPY services/api/ /app/.

If the file is not present in the catalog version when the build runs, the trigger fails with 422:

Dockerfile '<path>' not found in catalog <catalogId> version <catalogVersionId>.
Either upload a Dockerfile or use a generated dockerfile configuration. 

Your image must still meet the platform's container requirements—linux/amd64, non-root, a port between 1024 and 65535, an HTTP server, a readiness endpoint, and graceful SIGTERM handling.

Option 2: Use a generated Dockerfile

Set dockerfile.source to generated to have the platform write the Dockerfile for you:

"imageBuildConfig": {
  "dockerfile": {
    "source": "generated",
    "executionEnvironmentId": "67ab469cecdca772287de644",
    "executionEnvironmentVersionId": "6a216fca4244d434c38a2bd5",
    "entrypoint": ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"]
  }
} 
フィールド タイプ 必須 説明
source "generated" はい Selects this variant.
executionEnvironmentId 文字列 はい Execution environment used to resolve the base image. 24-character hexadecimal ID.
executionEnvironmentVersionId 文字列 はい Execution environment version that pins the exact base image tag. 24-character hexadecimal ID.
entrypoint array of strings はい The command baked into the generated image as CMD. At least one element.

The platform inspects your uploaded source, detects the project type, and writes a Dockerfile that installs your locked dependencies on top of the base image from the execution environment version.

entrypoint here is a build-time setting

imageBuildConfig.dockerfile.entrypoint becomes the CMD of the built image. It is unrelated to container.entrypoint, which overrides the command at runtime.

Supported project types for generated Dockerfiles

Detection is by filename at the root of the uploaded source. A lockfile is mandatory in both cases—builds install exactly what the lockfile pins, so that a build is reproducible.

言語 Package manager Required files at the upload root Install command
Python uv pyproject.toml and uv.lock uv sync --frozen --no-dev --no-install-project
Node.js npm package.json and package-lock.json npm ci --omit=dev

Detection checks for the Python files first. If a project's root has both a Python and a Node config—for example, a full-stack repo with a pyproject.toml/uv.lock backend and a package.json/package-lock.json frontend—the Python path always wins and the Node config is ignored, with no warning. Use a provided Dockerfile if you need to build the Node side of a project like this.

Not supported for generated Dockerfiles: requirements.txt and pip, Poetry, Yarn, pnpm, and non-Python/Node languages. Use a provided Dockerfile for anything outside the table.

The CLI generates a missing uv.lock for you

For Python projects, dr artifact code sync runs your local uv lock when pyproject.toml has no lockfile beside it, and uploads the result. Your uv configuration, private indexes, and credentials apply. Commit the generated file. An existing uv.lock is never modified.

Conflicting UV_FROZEN or UV_LOCKED base-image settings are cleared automatically

Some DataRobot-published execution environments (for example, GenAI Agents images) set UV_FROZEN=1 by default. Because uv rejects --frozen and --locked together, the generated Dockerfile unsets both UV_FROZEN and UV_LOCKED before running uv sync --frozen, so the build succeeds regardless of what the base image sets.

Node builds skip root lifecycle scripts

The generated Node Dockerfile removes preinstall, install, postinstall, prepare, and prepublishOnly from the root package.json before installing dependencies, because the full source tree isn't present yet at that point in the build. A project that relies on one of these to build output, generate code, or run a tool like husky install needs to produce that output before uploading, or use a provided Dockerfile that runs the step explicitly.

If detection fails, the build trigger returns 422 with a message that names the fix:

メッセージ Fix
Found pyproject.toml but no uv.lock. Run uv lock and re-sync your code (newer dr CLI versions generate it automatically during dr artifact code sync). Run uv lock, then re-sync. The CLI generates the lockfile for you during dr artifact code sync—this error means the upload reached the platform without one. Check that .drignore does not exclude uv.lock.
Found package.json but no package-lock.json. Run npm install to generate the lockfile and re-sync your code. Run npm install, then re-sync.
Found package.json with a yarn/pnpm lockfile, but only npm (package-lock.json) is currently supported. Generate a package-lock.json, or switch to a provided Dockerfile.
Unable to detect project runtime. Ensure the project contains a recognized config file (for example, pyproject.toml + uv.lock, or package.json + package-lock.json). Confirm the config and lockfile are at the root of the upload, not in a subdirectory.

基本イメージを選択する

For generated Dockerfiles, the base image comes from the execution environment version you name—the same mechanism used for custom models, jobs, applications, and notebooks. Any execution environment version works—DataRobot-published environments and your own custom environments alike—as long as the version resolves to an image.

The execution environment version must have a sourceDockerImageUri or an imageId. If it has neither, the build trigger fails with 422:

Execution environment version has neither sourceDockerImageUri nor imageId.
Cannot determine the base image for the generated Dockerfile. 

Known limitations of custom base images

The generated Dockerfile installs dependencies and nothing else—there is no apt-get step and no OS-level branching. A minimal base image can therefore build a package set that a DataRobot-published environment handles without trouble.

症状 原因 Fix
A dependency fails to compile during install The package ships only a source distribution and needs a C/C++ toolchain, which slim base images omit. Use a DataRobot-published execution environment, or a base image that includes build tools.
The container starts but crashes on import with a missing .so A wheel needs an OS shared library the base image lacks (for example, libgomp1 for onnxruntime). Use a base image that provides the library, or switch to a provided Dockerfile that installs it.
Many dependencies fail to install on an Alpine base Most Python wheels on PyPI target glibc, not musl. Use a glibc-based image, such as a Debian-derived one.

Builds also fetch a fallback uv binary from a public container registry, which requires outbound network access from the build environment.

Generated image layout

Knowing the layout helps when you write entrypoint and debug a container that starts but does not serve:

プロパティ 値
Working directory /app
Source location The whole upload is copied to /app
Python dependencies Virtual environment at /app/.venv, with /app/.venv/bin first on PATH
Node dependencies /app/node_modules, with /app/node_modules/.bin first on PATH
ユーザー Inherited from the base image, typically a non-root user
Dev dependencies Excluded (--no-dev / --omit=dev)
Command CMD set to your entrypoint; any base image entrypoint is cleared

Dependencies are installed from the lockfile as-is. Editing pyproject.toml without re-running uv lock does not fail the build—it silently installs the old lock. Re-run uv lock and re-sync whenever you change dependencies.

Build inputs the API does not expose

The following inputs are common in a Docker build but are either unsupported or fully managed by the platform, with no user-facing control.

使用できません 備考
Docker build arguments There is no buildArgs field. Bake values into the Dockerfile or supply them at runtime.
Build-time environment variables environmentVars on the container applies at runtime only; it is not visible to the build.
Build CPU, memory, or disk sizing Build resources are managed by the platform.
Build cache controls Layer caching is managed by the platform and cannot be turned off or primed per build.
Custom build timeouts Not configurable.

次のステップ

Configuring codeRef and the Dockerfile source is only the first step; the following resources cover triggering the build, diagnosing it, and the artifact lifecycle around it.

Goal Go here
Trigger a build and track it to completion Trigger and manage builds
Read the output of a build, or work out why one failed ビルドログ
Follow the whole flow end to end Tutorial: Build a Workload from source
Understand artifacts, lifecycle, and repositories アーティファクトの概念