---
id: azure--azure-blob-writer
title: "Blob writer"
summary: "Uploads text or a file stream to a blob in Azure Storage, or appends records to an append blob, and passes the input on. Sets content type, metadata and access tier, and can create the container."
audience: user
keywords: "input, output, authentication, connectionstring, accounturl, tenantid, clientid, clientsecret, sastoken, containername, createcontainer, blobname, writemode, overwrite, appendnewline, contenttype, accesstier, metadata"
---
# Blob writer

Uploads text or a file stream to a blob in Azure Storage, or appends records to an append blob, and passes the input on. Sets content type, metadata and access tier, and can create the container.

## Pins

| Pin | Kind | Types | Description |
|---|---|---|---|
| Input | input | `Viaducta.Plugins.TextPlugin.Types.TextRecord`, `Viaducta.Plugins.Files.Types.ViaFileStream` | Content to store: `TextRecord.Value` (UTF-8) or the stream. |
| Output | output | same as input | Called with the input record after a successful write. |

## Configuration

| Field | Type | Default | Description |
|---|---|---|---|
| `Authentication` | dropdown: `0` ConnectionString, `1` EntraId, `2` ServicePrincipal, `3` SasToken | `0` | How to sign in to the storage account. |
| `ConnectionString` | string | | Storage connection string. Required when `Authentication` is `0`. |
| `AccountUrl` | string | | Blob endpoint, for example `https://myaccount.blob.core.windows.net`, no query. Required when `Authentication` is `1`, `2` or `3`. |
| `TenantId` | string | | Entra ID tenant id. Required for `2`, optional for `1`. |
| `ClientId` | string | | `2`: client id of the app registration (required). `1`: client id of a user-assigned managed identity (optional). |
| `ClientSecret` | password | | Client secret of the app registration. Required for `2`. |
| `SasToken` | password | | Account or container SAS token with write permission (a leading `?` is ignored). Required for `3`. |
| `ContainerName` | string | | Target container. |
| `CreateContainer` | boolean | `false` | `true` creates the container (private) when it does not exist. |
| `BlobName` | string | | Target blob name including virtual folders, for example `exports/daily.csv`. Ending with `/` it is a folder and the record's name is appended (see Behaviour). |
| `WriteMode` | dropdown: `0` Block, `1` Append | `0` | `0`: one block blob upload per record. `1`: append blob, every record is appended. |
| `Overwrite` | boolean | `true` | Block: `true` replaces an existing blob; `false` fails the upload (HTTP 409) when the blob exists. |
| `AppendNewLine` | boolean | `true` | Append: add a line break (`\n`) after each `TextRecord`. |
| `ContentType` | string | | Content type of the blob, for example `text/csv`. Empty: the `ContentType` of the `TextRecord`, otherwise from the extension of the blob name (`.csv`, `.json`, `.jsonl`, `.xml`, `.txt`, `.pdf`, `.zip`, `.gz`, `.parquet`, images, ...), otherwise `application/octet-stream`. |
| `AccessTier` | dropdown: `0` Default, `1` Hot, `2` Cool, `3` Cold, `4` Archive | `0` | Block: tier of the uploaded blob; `0` uses the account's default tier. |
| `Metadata` | dictionary | | Name/value pairs stored as blob metadata (names must be valid C# identifiers). |

## Behaviour

- The storage client is created at flow start; missing sign-in fields fail the start. `1` EntraId uses the default Azure credential (managed identity of the host, workload identity, environment variables or Azure CLI); the identity needs the *Storage Blob Data Contributor* role (it covers `CreateContainer`). With `3` SasToken, `CreateContainer` needs an account SAS that allows the container resource type.
- Blob name: for a `TextRecord`, its `Name` replaces `BlobName`, or is appended when `BlobName` ends with `/`; without a `Name`, `BlobName` is used. For a `ViaFileStream`, `BlobName` is used; when it is empty the stream's `Name` is used, and when it ends with `/` the stream's `Name` is appended. An empty result fails the record.
- With `CreateContainer` the container is created on the first write of the run if it is missing.
- `0` Block: the content is uploaded with content type, metadata and tier. `1` Append: the append blob is created when missing (with content type and metadata), then the content is appended in blocks of up to 4 MB; following records and later runs append to the same blob.
- Then `Output` is called with the input record. Other input types fail with a "not supported" error. Storage errors (missing container, authentication, existing blob with `Overwrite` `false`, append to an existing block blob) raise an error.

## Notes

- `ViaFileStream` input: the content of `Stream` is uploaded from its current position; the stream stays open (it belongs to the component that opened it).
- Append blobs suit logs and JSON lines (`.jsonl`); appends of parallel writers interleave per record. An append blob holds at most 50,000 appends.
- `Archive` blobs can't be read until they are rehydrated (set the tier back with *Blob operation*).
- Store secrets as expression settings (`=Secrets.AzureStorage`).

## Example

```json
{ "Authentication": 1, "AccountUrl": "https://myaccount.blob.core.windows.net", "ContainerName": "exports", "CreateContainer": true, "BlobName": "daily/", "Metadata": { "source": "erp" } }
```

Timer → Sql query → Json serializer → **Blob writer** → Log (the `TextRecord.Name` of the serializer becomes the file in `daily/`)
