# Upload, Train, and Deploy a Model

This recipe takes a folder of labeled images and ends with a hosted Roboflow model you can call from your application. Each step is short — the whole flow is \~30 lines of Python.

## What you'll need

* A Roboflow workspace and API key — see [Find Your Roboflow API Key](/developer/authentication/find-your-roboflow-api-key.md).
* A folder of images plus matching annotations (COCO / VOC / YOLO).
* `Python >=3.10` and `pip install roboflow`.
* Time and credits to train (typically minutes for small datasets).

```bash
export ROBOFLOW_API_KEY=rf_xxxxx
```

## 1. Create the project

```python
import roboflow

rf = roboflow.Roboflow()
ws = rf.workspace()

project = ws.create_project(
    project_name="My Detector",
    project_type="object-detection",
    project_license="MIT",            # or "Private" on paid plans
    annotation="objects",              # what you're labeling
)
print(project.id)
```

If the project already exists, fetch it instead:

```python
project = ws.project("my-detector")
```

## 2. Upload the dataset

```python
ws.upload_dataset(
    "./my-images",                     # path to your dataset
    "my-detector",                     # project id
    num_workers=10,                    # parallel uploads
    project_type="object-detection",
)
```

The expected layout for a COCO dataset:

```
my-images/
├── train/
│   ├── image1.jpg
│   ├── image2.jpg
│   └── _annotations.coco.json
├── valid/
│   └── _annotations.coco.json
└── test/
    └── _annotations.coco.json
```

For VOC and YOLO, drop the corresponding annotation files alongside the images.

## 3. Generate a version

A version freezes a snapshot of the dataset with preprocessing and augmentation applied. The web app has a UI for this; from the SDK:

```python
new_version = project.generate_version({
    "preprocessing": {
        "auto-orient": True,
        "resize": {"width": 640, "height": 640, "format": "Stretch to"},
    },
    "augmentation": {},
})
version = project.version(new_version)
```

## 4. Train

```python
model = version.train(
    model_type="rfdetr-nano",          # see version.train help for full list
    epochs=100,
)
```

`train()` schedules the job server-side and returns once the queue accepts it. Check progress in the web app or via [`GET /:workspace/:project/jobs/:jobId`](/developer/rest-api/train-a-model.md).

## 5. Run inference

Once training completes, call the hosted model:

```python
predictions = version.model.predict("test-image.jpg", confidence=40, overlap=30).json()
for p in predictions["predictions"]:
    print(p["class"], p["confidence"])
```

That's the same hosted Serverless v2 endpoint the [REST API](/developer/rest-api/run-a-model-on-an-image.md) and [CLI `infer`](/developer/command-line-interface/run-a-model-on-an-image.md) hit.

## 6. (Optional) Move to a Dedicated Deployment

For high throughput or pinned latency, provision a [Dedicated Deployment](/developer/python-sdk/manage-dedicated-deployments.md) and point inference at its `public_url`:

```python
from roboflow.adapters import deploymentapi
from inference_sdk import InferenceHTTPClient

deploymentapi.add_deployment(
    api_key=ROBOFLOW_API_KEY,
    creator_email="me@company.com",
    deployment_name="my-deployment",
    machine_type="gpu-small",
    duration=8,
    delete_on_expiration=False,
    inference_version=None,
)

# poll deploymentapi.get_deployment until status == "ready", then:
status, info = deploymentapi.get_deployment(ROBOFLOW_API_KEY, "my-deployment")

client = InferenceHTTPClient(api_url=info["public_url"], api_key=ROBOFLOW_API_KEY)
print(client.infer("test-image.jpg", model_id="my-detector/3"))
```

## Variations

* **CI-driven retraining**: replace step 1's `create_project` with `project = ws.project(...)`, automate steps 2–4 in a GitHub Action that runs whenever new labeled images land in your data store. The CLI flavor (`roboflow upload`, `roboflow version create`, `roboflow train start`) makes the YAML cleaner.
* **Active-learning loop**: skip step 5 and use [`Workspace.active_learning()`](/developer/python-sdk/active-learning.md) to triage new images against the trained model and feed back the uncertain ones.
* **Custom weights**: skip steps 3–4 and use [`Version.deploy()`](/developer/python-sdk/upload-custom-model-weights.md) to upload an externally trained model into the version.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.roboflow.com/developer/recipes/upload-train-and-deploy.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
