---
title: Deployments and configurations
description: Deployments and configurations in the dltHub Runtime Python SDK (dlthub_sdk)
keywords: [dlthub, runtime, python sdk, dlthub_sdk, api]
---
# Deployments and configurations

<!-- generated from dlthub-client 0.28.8a3, do not edit -->

New to the SDK? [Getting started](getting-started.md) shows how to connect and use it.

## Deployments

### `Deployments` {#deployments}

The deployments of one workspace.

`list()` yields the newest version first.

#### `Deployments.upload()` {#deployments-upload}

```python
upload(*, code: bytes | BinaryIO, requirements: bytes | BinaryIO) -> Deployment
```

Store a new version of the workspace's code.

The platform derives the hash, the size and the file list by reading
the package. To skip an unchanged upload, compare the hash dlt's package
builder returned with `latest().content_hash`.

**Arguments**

| Name | Type | Description |
| --- | --- | --- |
| `code` | <code>bytes &#124; BinaryIO</code> | A deployment package built by dlt's package builder (a gzipped tar that carries dlt's `manifest.yaml`), as bytes or a binary file object. |
| `requirements` | <code>bytes &#124; BinaryIO</code> | The requirements manifest that goes with it, as bytes or a binary file object. Opaque to the SDK. |

**Returns:** <code><a href="#deployment">Deployment</a></code> — The stored deployment, one version above the last; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`BadRequest`](errors.md#badrequest) | The request was rejected as invalid; `message`, `code` and `fields` say why. |
| [`Conflict`](errors.md#conflict) | The current state does not allow the call, e.g. the workspace is archived; `code` and `message` say why. |
| [`DataplaneTokenRejected`](errors.md#dataplanetokenrejected) | The data plane rejected the token the platform issued for it. |
| [`InvalidResponse`](errors.md#invalidresponse) | The platform returned an upload address this SDK version cannot use; upgrade dlthub-client. |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |
| [`TransportError`](errors.md#transporterror) | The upload did not complete. A version is written only once the content arrives, but a request that never produced a response cannot say whether it did — read `latest()` before retrying. |

#### `Deployments.get()` {#deployments-get}

```python
get(*, version: int) -> Deployment
```

Return one deployment by version.

**Arguments**

| Name | Type | Description |
| --- | --- | --- |
| `version` | <code>int</code> | The version to read, counting up from 1. |

**Returns:** <code><a href="#deployment">Deployment</a></code> — The deployment; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`NotFound`](errors.md#notfound) | The workspace has no such version. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

#### `Deployments.latest()` {#deployments-latest}

```python
latest() -> Deployment
```

Return the deployment a run would use now.

**Returns:** <code><a href="#deployment">Deployment</a></code> — The newest version; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`NotFound`](errors.md#notfound) | The workspace has none yet. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

#### `Deployments.count()` {#deployments-count}

```python
count() -> int
```

Return how many versions the workspace holds.

**Returns:** <code>int</code> — The count; awaitable in async mode. Saturates at 10,001.

**Raises**

| Exception | When |
| --- | --- |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

#### `Deployments.list()` {#deployments-list}

```python
list(
    *,
    limit: int | None = None,
    offset: int = 0,
) -> Iterable[Deployment] | AsyncIterable[Deployment]
```

Yield the workspace's deployments, paging lazily.

**Arguments**

| Name | Type | Description |
| --- | --- | --- |
| `limit` | <code>int &#124; None</code> | Return at most this many. `None` walks to the end, or to row 10,100, past which the platform does not page. |
| `offset` | <code>int</code> | Skip this many, server-side. |

**Returns:** <code>Iterable[<a href="#deployment">Deployment</a>] &#124; AsyncIterable[<a href="#deployment">Deployment</a>]</code> — An iterable of deployments; async-iterable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |
| `ValueError` | A negative `limit` or `offset`. |

### `Deployment` {#deployment}

One uploaded version of a workspace's code.

**Attributes**

| Name | Type | Description |
| --- | --- | --- |
| `version` | <code>int</code> | Version number within the workspace, starting at 1 and incremented by each upload. |
| `id` | <code>str</code> | Unique ID (a UUID). |
| `content_hash` | <code>str</code> | Hash of the package contents: base64 SHA3-256 over each file's path and digest, as dlt computes when building the package; identical file sets give identical hashes. |
| `file_count` | <code>int</code> | Number of files in the package. |
| `size_bytes` | <code>int</code> | Size of the uploaded package in bytes. |
| `requirements_size_bytes` | <code>int</code> | Size of the uploaded requirements file in bytes. |
| `created_at` | <code>datetime</code> | When it was created. |
| `created_by` | <code>str</code> | The `organization_membership_id` of the member who uploaded it. |
| `updated_at` | <code>datetime</code> | When it was last changed. |

#### `Deployment.files()` {#deployment-files}

```python
files() -> tuple[FileEntry, ...]
```

List the files this deployment holds.

The manifest is stored with the content rather than with the record,
so this is a fresh read every time.

**Returns:** <code>tuple[<a href="#fileentry">FileEntry</a>, ...]</code> — One entry per file, in the platform's order; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`DataplaneTokenRejected`](errors.md#dataplanetokenrejected) | The data plane rejected the token the platform issued for it. |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`NotFound`](errors.md#notfound) | The deployment no longer exists. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

## Configurations

### `Configurations` {#configurations}

The configurations of one workspace.

`list()` yields the newest version first.

#### `Configurations.upload()` {#configurations-upload}

```python
upload(*, data: bytes | BinaryIO) -> Configuration
```

Store a new version of the workspace's configuration.

The platform reads the package for the hash, the file list and the
profile names. To skip an unchanged upload, compare the hash dlt's
package builder returned with `latest().content_hash`.

**Arguments**

| Name | Type | Description |
| --- | --- | --- |
| `data` | <code>bytes &#124; BinaryIO</code> | A configuration package built by dlt's package builder (a gzipped tar of the `.dlt` settings folder that carries dlt's `manifest.yaml`), as bytes or a binary file object. |

**Returns:** <code><a href="#configuration">Configuration</a></code> — The stored configuration, one version above the last; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`BadRequest`](errors.md#badrequest) | The request was rejected as invalid; `message`, `code` and `fields` say why. |
| [`Conflict`](errors.md#conflict) | The current state does not allow the call, e.g. the workspace is archived; `code` and `message` say why. |
| [`DataplaneTokenRejected`](errors.md#dataplanetokenrejected) | The data plane rejected the token the platform issued for it. |
| [`InvalidResponse`](errors.md#invalidresponse) | The platform returned an upload address this SDK version cannot use; upgrade dlthub-client. |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |
| [`TransportError`](errors.md#transporterror) | The upload did not complete. A version is written only once the content arrives, but a request that never produced a response cannot say whether it did — read `latest()` before retrying. |

#### `Configurations.get()` {#configurations-get}

```python
get(*, version: int) -> Configuration
```

Return one configuration by version.

**Arguments**

| Name | Type | Description |
| --- | --- | --- |
| `version` | <code>int</code> | The version to read, counting up from 1. |

**Returns:** <code><a href="#configuration">Configuration</a></code> — The configuration; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`NotFound`](errors.md#notfound) | The workspace has no such version. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

#### `Configurations.latest()` {#configurations-latest}

```python
latest() -> Configuration
```

Return the configuration a run would use now.

**Returns:** <code><a href="#configuration">Configuration</a></code> — The newest version; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`NotFound`](errors.md#notfound) | The workspace has none yet. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

#### `Configurations.count()` {#configurations-count}

```python
count() -> int
```

Return how many versions the workspace holds.

**Returns:** <code>int</code> — The count; awaitable in async mode. Saturates at 10,001.

**Raises**

| Exception | When |
| --- | --- |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

#### `Configurations.list()` {#configurations-list}

```python
list(
    *,
    limit: int | None = None,
    offset: int = 0,
) -> Iterable[Configuration] | AsyncIterable[Configuration]
```

Yield the workspace's configurations, paging lazily.

**Arguments**

| Name | Type | Description |
| --- | --- | --- |
| `limit` | <code>int &#124; None</code> | Return at most this many. `None` walks to the end, or to row 10,100, past which the platform does not page. |
| `offset` | <code>int</code> | Skip this many, server-side. |

**Returns:** <code>Iterable[<a href="#configuration">Configuration</a>] &#124; AsyncIterable[<a href="#configuration">Configuration</a>]</code> — An iterable of configurations; async-iterable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |
| `ValueError` | A negative `limit` or `offset`. |

### `Configuration` {#configuration}

One uploaded version of a workspace's configuration.

**Attributes**

| Name | Type | Description |
| --- | --- | --- |
| `version` | <code>int</code> | Version number within the workspace, starting at 1 and incremented by each upload. |
| `id` | <code>str</code> | Unique ID (a UUID). |
| `content_hash` | <code>str</code> | Hash of the package contents: base64 SHA3-256 over each file's path and digest, as dlt computes when building the package; identical file sets give identical hashes. |
| `file_count` | <code>int</code> | Number of files in the package. |
| `size_bytes` | <code>int</code> | Size of the uploaded package in bytes. |
| `profiles` | <code>tuple[str, ...]</code> | Profile names found in `<profile>.config.toml` / `<profile>.secrets.toml` file names, sorted. |
| `created_at` | <code>datetime</code> | When it was created. |
| `created_by` | <code>str</code> | The `organization_membership_id` of the member who uploaded it. |
| `updated_at` | <code>datetime</code> | When it was last changed. |

#### `Configuration.files()` {#configuration-files}

```python
files() -> tuple[FileEntry, ...]
```

List the files this configuration holds.

The manifest is stored with the content rather than with the record,
so this is a fresh read every time.

**Returns:** <code>tuple[<a href="#fileentry">FileEntry</a>, ...]</code> — One entry per file, in the platform's order; awaitable in async mode.

**Raises**

| Exception | When |
| --- | --- |
| [`DataplaneTokenRejected`](errors.md#dataplanetokenrejected) | The data plane rejected the token the platform issued for it. |
| [`NotAuthorized`](errors.md#notauthorized) | The caller lacks the access this call needs; `message` says why. |
| [`NotFound`](errors.md#notfound) | The configuration no longer exists. |
| [`ScopeMissing`](errors.md#scopemissing) | Reached without a workspace in scope. |

## Files

### `FileEntry` {#fileentry}

One file the platform holds for a deployment or a configuration.

**Attributes**

| Name | Type | Description |
| --- | --- | --- |
| `relative_path` | <code>str</code> | Path of the file inside the package, with `/` separators: relative to the workspace root for a deployment, and to the `.dlt` settings folder for a configuration. |
| `size_bytes` | <code>int</code> | Size of the file in bytes; 0 for a symlink. |
| `sha3_256` | <code>str</code> | Base64 SHA3-256 of the file contents, or of the `linkname` string for a symlink. |
| `linkname` | <code>str &#124; None</code> | Symlink target; set for symlink entries only. |
