# Tutorial: Deploy from a project folder

> Tutorial: Deploy from a project folder - Deploy an app to DataRobot from its source folder with dr
> workload up, then change it and redeploy with the same command.

This Markdown file sits beside the HTML page at the same path (with a `.md` suffix). It summarizes the topic and lists links for tools and LLM context.

Companion generated at `2026-10-29T19:22:57.391335+00:00` (UTC).

## Primary page

- [Tutorial: Deploy from a project folder](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md): Full documentation for this topic (Markdown sidecar).

## Sections on this page

- [Prerequisites](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#prerequisites): In-page section heading.
- [Describe the project](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#describe-the-project): In-page section heading.
- [Deploy](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#deploy): In-page section heading.
- [Change a variable and redeploy](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#change-a-variable-and-redeploy): In-page section heading.
- [What happened](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#what-happened): In-page section heading.
- [What triggers a rebuild](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#what-triggers-a-rebuild): In-page section heading.
- [Keep.envand.datarobot.yamlin sync](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#keep-env-in-sync): In-page section heading.
- [Lock the version that is serving](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#lock-the-version-that-is-serving): In-page section heading.
- [Operate the Workload](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#operate-the-workload): In-page section heading.
- [Run it in CI](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#run-it-in-ci): In-page section heading.
- [Clean up](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#clean-up): In-page section heading.
- [Summary](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#summary): In-page section heading.
- [Next steps](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#next-steps): In-page section heading.

## Related documentation

- [Workload API](https://docs.datarobot.com/en/docs/workload-api/index.html.md): Linked from this page.
- [Get started: Workload API](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/index.html.md): Linked from this page.
- [Tutorial: Hello, Workload](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-hello-world.html.md): Linked from this page.
- [DataRobot CLI](https://docs.datarobot.com/en/docs/workload-api/workload-interfaces/workload-cli/workload-cli.html.md): Linked from this page.
- [Workload manifest](https://docs.datarobot.com/en/docs/workload-api/workload-interfaces/workload-cli/workload-manifest.html.md): Linked from this page.
- [Promote a Workload to production](https://docs.datarobot.com/en/docs/workload-api/update-workloads/promote-production.html.md): Linked from this page.
- [Tutorial: Deploy a production-ready container](https://docs.datarobot.com/en/docs/workload-api/create-workloads/tutorial-production-ready-container.html.md): Linked from this page.
- [Tutorial: Replace the artifact behind a running Workload](https://docs.datarobot.com/en/docs/workload-api/update-workloads/tutorial-replace-artifacts.html.md): Linked from this page.

## Documentation content

> [!NOTE] Premium feature
> The Workload API is a premium feature. Contact your DataRobot representative or administrator for information on enabling the feature.

This tutorial deploys an app to DataRobot from the folder its code lives in, with one command, and keeps it running from the same folder. In about ten minutes you'll describe a project with `dr workload config`, deploy it with `dr workload up`, change an environment variable and watch the change roll out without a rebuild, lock the version that is serving, and tear everything down.

Where [Tutorial: Hello, Workload](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-hello-world.html.md) starts from a published image and a spec file, this tutorial starts from source. The CLI builds the image on the platform, creates the artifact and the Workload, and on every later run compares the folder with what is running and applies only the difference.

## Prerequisites

- The DataRobot CLI ( dr ), version 0.13 or later, authenticated with dr auth login .
- A project folder with a Dockerfile at its root. The CLI gets your app's port from the EXPOSE line in its Dockerfile (for example, EXPOSE 8080 ). Use port 1024 or higher, because containers don't run as root and can't use ports below 1024.

The project used here is a FastAPI app that answers `GET /` with a greeting read from an environment variable:

```
hello-up/
├── app.py
├── Dockerfile
└── .env
```

```
# app.py
import os

from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def hello():
    return {"message": os.environ.get("GREETING", "hello")}
```

```
# Dockerfile
FROM python:3.12-slim
RUN pip install --no-cache-dir fastapi uvicorn
COPY app.py .
EXPOSE 8080
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8080"]
```

```
# .env
GREETING=hello world
```

## Describe the project

Run the setup wizard from the project folder. It reads the Dockerfile and the `.env`, asks only what it cannot infer, and writes `.datarobot.yaml`:

```
cd hello-up
dr workload config
```

The wizard asks for a Workload name, confirms the image source and port it read from the Dockerfile, asks for the sizing (CPU, memory, and replicas), and offers to carry the variables in `.env` into the file. A value that looks like a secret, such as a long random token or a URL with a password in it, is stored as a credential on the platform and referenced from the file as `dr-credential:<credentialId>/<key>` rather than written into it. The last screen shows the file before it is written.

The result is a plain Workload spec with one extra key the CLI manages:

```
# .datarobot.yaml
name: hello-up
importance: low

artifact:
  name: hello-up-artifact
  type: service
  spec:
    containerGroups:
      - name: default
        containers:
          - name: primary
            primary: true
            port: 8080
            imageBuildConfig:
              dockerfile:
                source: provided
            environmentVars:
              - name: GREETING
                value: hello world

runtime:
  containerGroups:
    - replicaCount: 1
      containers:
        - name: primary
          resourceAllocation: {cpu: 0.5, memory: 512MB}
```

Every question has a flag, so the same file can be written without a terminal:

```
dr workload config --yes --name hello-up
```

Commit `.datarobot.yaml`. After the first deploy it also records the Workload's ID, and every later deploy reads it to find that Workload. For the full file reference, see the [Workload manifest](https://docs.datarobot.com/en/docs/workload-api/workload-interfaces/workload-cli/workload-manifest.html.md).

## Deploy

Deploy the folder.`up` prints a plan, then carries it out:

```
dr workload up
```

```
# Output
  + workload   hello-up will be created, with its first artifact
  ~ code       all project files, uploaded for the first time
  ✓ Creating the artifact (500ms)
  ✓ Syncing code (3.1s)
  ✓ Building the image (3m12s)
  ✓ Creating workload (1.1s)
  ✓ Waiting for the workload to run (5.8s)
  ✓ Checking the endpoint (300ms)
  Endpoint check: an authenticated GET answered HTTP 200 OK.

  ✓ Workload endpoint: https://app.datarobot.com/api/v2/endpoints/workloads/68b0c1d2e3f4a5b6c7d8e9f0/

  ⚠ This workload is running a draft artifact.
    Draft workloads are stopped after 8 hours, whether or not they are in use.
    Run 'dr workload promote' to version the artifact and make it permanent.

Next:
  dr workload promote  Version the artifact to make it permanent
  dr workload logs     View the container logs
  dr workload status   Check the workload status
```

The first deploy of a project with a Dockerfile takes as long as the image build does, usually a few minutes. The build logs stream live under the build step.`up` waits for the Workload to reach `running`, then sends one GET to its endpoint and reports the answer; an app that is still starting can answer `503` there, which is reported, not treated as a failure. Pass `--detach` to return once the deploy is requested instead.

Call the endpoint. The URL ends with a slash, so append paths without a leading one:

```
curl -sS "$(dr workload endpoint)" -H "Authorization: Bearer $DATAROBOT_API_TOKEN"
```

```
# Output
{"message": "hello world"}
```

No Workload ID was passed to `dr workload endpoint`. Every `dr workload` command that takes an ID reads it from `.datarobot.yaml` when run inside the project, and says on stderr which Workload it picked.

To see what a run would do without doing it, pass `--dry-run`. On a project that has never deployed, it also prints the `.datarobot.yaml` it would write, so `dr workload up --yes --dry-run` is a one-command preview of a fresh project.

## Change a variable and redeploy

Change the greeting in `.datarobot.yaml`:

```
            environmentVars:
              - name: GREETING
                value: hello again
```

Run the same command. The output lists only what has changed:

```
dr workload up
```

```
# Output
  .env gives 1 declared variable a different value from the manifest, and the manifest is what deploys: GREETING.
    Apply it with 'dr workload up --sync-env'.
hello-up (68b0c1d2), running

  ~ artifact   1 spec change, written to the draft in place; keeps the running image, so no rebuild
      env GREETING: changed
  ✓ Rolling out the change (300ms)
  ✓ Waiting for the rollout (11s)
  ✓ Waiting for the new version to serve (1m2s)
  ✓ Checking the endpoint (200ms)
  Endpoint check: an authenticated GET answered HTTP 200 OK.
```

The note at the top of the output is expected. You changed `GREETING` in `.datarobot.yaml` but not in `.env`, and as a result the two files no longer match. Deployments use the values in `.datarobot.yaml`, so you don't need to do anything—the note is for your information. See [Keep.envand.datarobot.yamlin sync](https://docs.datarobot.com/en/docs/workload-api/get-started-workloads/tutorial-deploy-from-folder.html.md#keep-env-in-sync) for more information.

### What happened

- No rebuild: The container reads environment variables when it starts, so the existing image is reused.
- Versioning: If the artifact is still a draft, the change updates the draft. If the artifact is locked, the change creates a new version.
- No downtime: The current version keeps serving requests until the new one is ready. The endpoint URL stays the same.

### What triggers a rebuild

| You change | Result |
| --- | --- |
| An environment variable, the port, the health check, or the image reference | Updates the artifact (or creates a new version if it's locked). No rebuild. |
| Your code or the Dockerfile | Builds a new image. |
| Only sizing, such as replicaCount or resourceAllocation | Applied in place. No new version. |

Call the endpoint again:

```
curl -sS "$(dr workload endpoint)" -H "Authorization: Bearer $DATAROBOT_API_TOKEN"
```

```
# Output
{"message": "hello again"}
```

If nothing has changed, `dr workload up` prints `Already up to date` and exits with code `0`. That makes it safe to run automatically on every push.

### Keep .env and .datarobot.yaml in sync

`.datarobot.yaml` is the only file `dr workload up` deploys from. It never reads `.env` at deploy time.

To copy changes from `.env` into `.datarobot.yaml`, run:

```
dr workload up --sync-env
```

It shows which variables it will add, change, or remove, asks you to confirm, and then deploys.

Neither file is uploaded with your code—the starter `.drignore` file excludes `.env`, `.datarobot.yaml`, and the local state directory. Editing them doesn't count as a code change, so it never triggers a rebuild.

## Lock the version that is serving

Each deploy so far created a draft artifact version, which the platform keeps for eight hours. Once a version is right, make it permanent:

```
dr workload promote
```

```
# Output
Promoted workload 68b0c1d2e3f4a5b6c7d8e9f0: artifact 68b0c1d2e3f4a5b6c7d8e9f1 is locked as version 1.
```

Promotion locks the artifact in place; nothing is rebuilt or rolled, and a second `promote` is refused because the artifact is already locked. Locking is one-way, so the next `up` that changes something creates a new version rather than editing this one, and locks it to match. A Workload that has been promoted once keeps deploying as locked versions without `--promote` being passed again. A dry run after the promotion shows the difference:

```
# Output of dr workload up --dry-run after a further change
hello-up (68b0c1d2), running

  ~ lock       the running version is locked, so a new one is created and permanently locked to match
  + artifact   new version, 1 spec change; keeps the running image, so no rebuild
      env GREETING: changed

Dry run: nothing was changed.
```

To lock at the end of a deploy in one step, run `dr workload up --promote`. For what promotion changes on the platform, see [Promote a Workload to production](https://docs.datarobot.com/en/docs/workload-api/update-workloads/promote-production.html.md).

## Operate the Workload

The day-two commands all find the Workload from the folder:

```
# Status as a bare value, for scripts
dr workload status

# Why a Workload is in its state, per replica and container
dr workload diagnose

# Container logs, filtered
dr workload logs --level error --since 1h --follow

# What the platform did to the Workload: rollouts, starts, stops
dr workload events

# Scale right now; the next dr workload up puts back the replicaCount from .datarobot.yaml
dr workload settings --replicas 2 --wait
```

For the full list of `dr workload` commands and their options, see [Manage Workloads with the CLI](https://docs.datarobot.com/en/docs/workload-api/workload-interfaces/workload-cli/workload-cli.html.md).

## Run it in CI

In a CI pipeline, add `--yes` so `dr workload up` runs without prompts, even for a project that has never been deployed:

```
dr workload up --yes --output-format json
```

What it does depends on whether the project has a `.datarobot.yaml` file:

- No.datarobot.yaml: It fills in the settings from your project files, writes .datarobot.yaml , and deploys.
- A committed.datarobot.yaml: It deploys only what changed since the last deployment.

To turn off prompts for every `dr` command in the pipeline, set `DATAROBOT_CLI_NON_INTERACTIVE=true` once instead of adding `--yes` to each command.

With `--output-format json`, the command writes one JSON document to stdout with the plan and the result. If it fails, it writes a JSON error to stderr and exits with a non-zero code.

> [!WARNING] Commit.datarobot.yaml
> Commit `.datarobot.yaml` to your repository before you run `dr workload up --yes` in CI. Without a committed `.datarobot.yaml`, every run creates a new Workload.

## Clean up

Delete the Workload and everything the deploy created beside it:

```
dr workload delete --purge
```

Along with the Workload, `--purge` deletes:

- The draft artifact the Workload ran.
- The credentials this project created.
- The local .datarobot/workload/ folder.

The output lists each item it deletes and each item it keeps.

Locked artifacts are kept.A locked artifact can't be deleted. Because you promoted the Workload earlier in this tutorial, its artifact is locked, so `--purge` keeps it. It also keeps the credentials, because anything that runs that artifact might still need them.

The command also removes the `workloadId` line from `.datarobot.yaml`. The next `dr workload up` from this folder creates a new Workload from scratch.

```
# Output
Deleted workload: 68b0c1d2e3f4a5b6c7d8e9f0
Removed workloadId from .datarobot.yaml; this project no longer points at a workload.
Removed /home/me/hello-up/.datarobot/workload
Kept artifact 68b0c1d2e3f4a5b6c7d8e9f1: it is locked, and a locked artifact cannot be deleted
Kept the credentials: artifact 68b0c1d2e3f4a5b6c7d8e9f1 survived, and whatever runs it may read them
```

## Summary

You described a project once, deployed it with one command, redeployed a configuration change without a rebuild, locked the version that was serving, and tore it all down. The folder is the source of truth: `.datarobot.yaml` says what runs, and `dr workload up` makes it true.

## Next steps

| Resource | Description |
| --- | --- |
| Workload manifest | Every key in .datarobot.yaml, the three image sources, what up manages, and how it decides between a rebuild, a rollout, and an in-place change. |
| Manage Workloads with the CLI | The dr workload reference, including every config and up flag. |
| Tutorial: Deploy a production-ready container | Sharing, importance, and monitoring for a Workload that serves real traffic. |
| Tutorial: Replace the artifact behind a running Workload | What a rollout does on the platform, which is what up drives for you. |
