---
id: azure--azure-blob-enumerator
title: "Blob enumerator"
summary: "Lists the blobs of an Azure Storage container, optionally filtered by a name prefix and skipping blobs with a given index tag, and emits one file info record per blob. Use it with *Blob reader* to process the files of a container."
audience: user
keywords: "input, output, continue, authentication, connectionstring, accounturl, tenantid, clientid, clientsecret, sastoken, containername, prefix, skiptag, toplevelonly, namepattern, minageminutes, orderby, maxblobs"
---
# Blob enumerator

Lists the blobs of an Azure Storage container, optionally filtered by a name prefix and skipping blobs with a given index tag, and emits one file info record per blob. Use it with *Blob reader* to process the files of a container.

## Pins

| Pin | Kind | Types | Description |
|---|---|---|---|
| Input | input | any | Starts the enumeration (for example a timer). |
| Output | output | `Viaducta.TypeSystem.Metadata.ViaFileInfo` | Called once per blob. |
| Continue | continue output | same as input | Called with the input record after the last blob. |

## 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 (`DefaultEndpointsProtocol=https;AccountName=...;AccountKey=...` or a SAS 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 (`sv=...&sig=...`, a leading `?` is ignored). Required for `3`. |
| `ContainerName` | string | | Required. Container to list. |
| `Prefix` | string | | Optional blob name prefix, for example `incoming/2026/`. Empty lists all blobs. |
| `SkipTag` | string | | Blob index tag name; blobs that have this tag are not listed (for example `viaducta-processed`, set by *Blob reader* post-processing `3` Tag). Empty lists all. |
| `TopLevelOnly` | boolean | `false` | `true` lists only the blobs directly under `Prefix` (end it with `/`), not those in deeper virtual folders. |
| `NamePattern` | string | `*` | Only blobs whose name after the last `/` matches; `*` and `?` as wildcards, case-insensitive, for example `*.csv`. |
| `MinAgeMinutes` | integer | `0` | Only blobs not modified for at least this many minutes, so blobs still being written are skipped. `0` lists all. |
| `OrderBy` | dropdown: `0` Name, `1` LastModified, `2` CreateTime | `0` | Emit order: by name (ordinal), or oldest modification / creation first. |
| `MaxBlobs` | integer | `0` | Emit at most this many blobs per run, the first ones in `OrderBy` order. `0` emits all. |

## Behaviour

- The storage client is created at flow start. `1` EntraId uses the default Azure credential: the managed identity of the host (system-assigned, or the user-assigned one of `ClientId`), workload identity, environment variables or the Azure CLI sign-in. The identity needs the *Storage Blob Data Reader* role (*Storage Blob Data Owner* to read tags with `SkipTag`).
- Per input the whole listing is read first (flat: virtual folders are part of the name and all levels are returned; with `TopLevelOnly` only the blobs directly under `Prefix`), filtered by `SkipTag`, `NamePattern` and `MinAgeMinutes`, ordered by `OrderBy` and cut to `MaxBlobs`; then the blobs are emitted. Changes downstream components make in the container during the run (for example *Blob reader* moving blobs) don't change the list.
- Each blob is emitted as `ViaFileInfo`: `FileName` = blob name (including virtual folders), `FilePath` = blob URL `<container URL>/<blob name>` (URL-escaped, without query string or SAS token), `Size` = content length, `CreateDateTime` = creation time (UTC), `LastAccessDateTime` = last access time (UTC; `DateTime.MinValue` when access tracking is off).
- The progress bar shows `<emitted>/<total> blobs` (while a large container is listed: `listing, <n> blobs`); the run ends with the status `<emitted>/<total> blobs listed`.
- After the last blob `Continue` is called with the input record.

## Notes

- Connect `Output` to *Blob reader* to read each listed blob: the reader takes container and blob from `FilePath` (leave its `ContainerName`/`BlobName` empty). With post-processing in the reader (delete, move, tag + `SkipTag`) a timer-driven flow processes each blob once.
- The listing is kept in memory for the run; use `Prefix` to narrow very large containers. `MaxBlobs` limits what is emitted, not what is listed.
- `MaxBlobs` with `OrderBy` `1` and reader post-processing processes a backlog oldest first in slices, one slice per timer run.
- The container is part of `FilePath` (the blob URL); *Blob reader* and *Blob operation* take it from there.
- Store secrets as expression settings and reference them (`=Secrets.AzureStorage`) instead of typing keys into the flow.

## Example

```json
{ "Authentication": 1, "AccountUrl": "https://myaccount.blob.core.windows.net", "ContainerName": "imports", "Prefix": "daily/", "SkipTag": "viaducta-processed", "NamePattern": "*.csv", "MinAgeMinutes": 5, "OrderBy": 1, "MaxBlobs": 100 }
```

Timer → **Blob enumerator** → Blob reader → CSV decoder → ...
