Last updated: 2026-10-06

Azure Storage: Blob, Data Lake (ADLS Gen2), File Shares, Queues and Tables

Jam SQL Studio connects to Azure Storage accounts, to a single SAS-scoped resource, and to the Azurite emulator. Browse blob containers and virtual folders, find blobs and files by part of a name or an extension, preview and edit files in a pane next to the list, upload or download files and folders, and manage long-running work in the Transfers drawer. Object Explorer also lists queues, tables and file shares: a queue tab peeks messages without consuming them, a table opens in a grid where you filter, page and edit its typed entities, and a file share opens in the same browser as a container, with its snapshots, quota and mount commands. On an account with a hierarchical namespace (ADLS Gen2), containers open in a Data Lake view with real directories, rename and move, and access control lists (ACLs). An Azure subscription connection lists the managed disks and disk snapshots of its resource groups.

This release covers blobs, queues, tables, file shares (SMB and NFS), Data Lake (ADLS Gen2) directories and managed disks. Azure Storage connections do not run SQL — see What does not apply.

Add a connection

Open New connection and pick Azure Storage as the engine. Connect using, the first row of the form's Storage section, picks what the connection points at, and the fields below it follow the choice:

  • Storage account — type the account name in the Storage account field, paste an endpoint URL (https://contoso.blob.core.windows.net), or paste a full connection string (DefaultEndpointsProtocol=https;AccountName=…;AccountKey=…). Tick the services you want verified.
  • Emulator (Azurite) — fills the well-known emulator account, key and ports 10000–10002, and shows a copyable docker run command if you don't have Azurite running yet — it publishes the ports the connection's endpoints use, so a connection moved to other ports gets a matching command. Pasting UseDevelopmentStorage=true does the same, and so does pasting the full Azurite connection string, with the ports and account it names (see Azurite and local containers).
  • Azure subscription — enter a subscription ID, or a resource group's resource ID (/subscriptions/…/resourceGroups/…) to reach that resource group only. The connection lists managed disks and disk snapshots (see Managed disks) and signs in with Microsoft Entra ID only.
  • Single resource — paste into the Resource URL field a container, folder or blob URL, with or without a SAS token, or a file share, share folder or share file URL with its SAS. The connection is scoped to exactly that resource and never lists its siblings. See Share SAS URLs for the file / folder choice.

Don't want to type the account name? Click Browse Azure to pick a storage account straight from your signed-in Azure account — endpoints, services and the portal link are filled in for you. See the Browse Azure guide.

To make the connection read-only, tick Open read-only in the Access row, the last row of the Storage section (the same row SQLite connections have). Browsing, downloads and queue peeks stay available; uploads, deletes, new folders and containers, tier and metadata changes, and queue and entity changes are turned off, for you and for AI agents, each with the reason Connection is read-only (edit connection to change). To change it later, open Edit connection and tick or untick the same box. Saving the change closes the connection if it is open, and the next connect uses the new setting.

The New Connection dialog on the Azure Storage form: Connect using (Storage account, Emulator (Azurite), Single resource), the Storage account field with its Browse Azure button, Account key authentication with the key masked, and the Blob, Table, Queue and File shares service checkboxes.
The connection form adapts to Azure Storage: three connect modes, the Azure authentication methods, and a tick per service to verify.

Authentication

MethodWhat you enterGood for
Account KeyThe storage account key (or a connection string that carries it)Full access to the account
Shared Access SignatureA SAS token, or a URL with the token on itScoped, time-limited access — account, service, or stored-policy SAS
AnonymousNothing — just the public URLA container or blob with public read access (single-resource mode only)
Microsoft Entra ID (Interactive Browser)A browser sign-in (MFA supported)Your own account, with the data roles you hold
Service PrincipalTenant ID, client ID, client secretAutomation and shared credentials
Azure CLINothing — reuses a prior az loginMachines where you already sign in with the CLI

Microsoft Entra ID: which role each operation needs

Azure splits storage permissions in two. Listing containers, tables and queues is a management action that any Reader, Contributor or Owner role includes. Reading or changing what is inside them needs a data role, which those three roles do not include. An identity with only Reader can therefore connect and see every container name, yet opening a container fails with “This request is not authorized to perform this operation using this permission.”

OperationRole it needs (on the storage account, or on that container / table / queue)
List containers, tables, queuesReader (or any data role below)
List and download blobs, read propertiesStorage Blob Data Reader
Upload, delete, create containers, edit metadata and tiersStorage Blob Data Contributor
Query table entitiesStorage Table Data Reader
Write entities, create or delete tablesStorage Table Data Contributor
Peek queue messagesStorage Queue Data Reader
Send, receive, update, delete or clear messagesStorage Queue Data Contributor
User-delegation SASStorage Blob Delegator
List file shares, read a share's quota, usage and snapshotsReader, or another role that can read the storage account (the Storage File Data roles do not include it)
List and download files in a share, read file propertiesStorage File Data Privileged Reader
Upload, delete, create folders in a shareStorage File Data Privileged Contributor
Create, resize, snapshot or delete file shares; change their stored access policiesStorage Account Contributor or Contributor (a management role)

When a data role is missing, the error in the storage browser, the table and queue views, the Transfers drawer and the MCP tools names the role and where to assign it (Azure portal → the storage account → Access control (IAM)). A new role assignment can take a few minutes to apply. The storage browser, the table view and the queue view show such a refusal the same way: a short title, the cause in one line, Ways to fix (the role to assign, and the account-key option or why it is not offered), Retry, and under Details the whole refusal as one sentence — the role, where it is needed and where to assign it, the same sentence the Transfers drawer and the MCP tools give — in place of Azure's, which names no role. The account-key option is stated once, in Ways to fix, with whether this identity may use it. While the data is refused, Upload, New folder, Delete, the table's Edit Mode and the queue's Add message, Receive and Clear queue stay unavailable and say which role they need, and so does a share's Download folder, which lists the folder first; files dropped onto the tab are not uploaded either. A refused file share behaves like a refused container. The container's or share's own Properties stays available: Azure authorizes reading them separately from listing the contents, so the panel tries the read and shows its own error if that is refused too. The guide to Azure Storage authorization errors maps each error code that Azure, Azure Storage Explorer, az and AzCopy show to its cause, including the ones a role does not fix (firewall, SAS permissions, disabled Shared Key, the wrong tenant).

A request refused with AuthorizationFailure keeps Azure's own message. Azure uses that code when the account's firewall or network rules, or disabled public network access, block your address, and for role conditions, so the error lists those causes first and names the data role only as a possible one.

If your identity holds a data role on one container, table or queue but no role on the account, it cannot list the account and the connection fails. The error then suggests attaching that one resource instead: choose Single resource under Connect using and paste the container, table or queue URL (no SAS is needed when you sign in with Microsoft Entra ID).

Use the account key for data access

Like the Azure portal's Switch to access key, a Microsoft Entra connection can read data with the storage account key instead of data roles, provided the identity may read the account keys (the listKeys permission, included in Storage Account Key Operator Service Role, Reader and Data Access, Contributor and Owner). Keys give full data access and bypass role assignments, so this is always your explicit choice:

  • In the connection form, set Data access to Account key, read by this identity through Azure Resource Manager. The optional Storage account resource ID is looked up by account name when empty; that lookup needs Reader on the account's subscription or resource group.
  • Or, when opening a container, table or queue fails for a missing data role, the error offers Use the account key for data access. It appears when this identity may read the keys; otherwise the error says why (no listKeys permission, the account disallows Shared Key authorization, the account could not be found, or one of the checks below failed). To decide, Jam SQL Studio reads the account from Azure Resource Manager and asks what this identity may do on it; it never reads a key before you choose this option. When Azure refuses to say what the identity may do, or Azure Resource Manager does not answer, the offer says which of the two happened and that the permission could not be confirmed, and reads Try the account key for data access. If the switch then fails because the identity cannot read the keys, the connection goes back to its previous data access.

The key is only read for the account the connection actually talks to. Before any key is read, Jam SQL Studio checks that:

  • every endpoint belongs to the connection’s Azure environment. The key is read through that environment’s Azure Resource Manager (management.azure.com on public Azure), so an endpoint of another cloud is refused.
  • every endpoint the connection uses is the account's own endpoint as Azure Resource Manager reports it. An endpoint override (under More options) that differs, such as a private endpoint host or another domain, is refused.
  • a saved Storage account resource ID names this account. A resource ID for another account is refused rather than replaced by a lookup. When the lookup by name finds several accounts with that name (in different subscriptions or tenants), you are asked to set the resource ID.

The key is read with the connection's own identity each time it connects. It is never saved by the application: not with the connection, in sessions, in logs or in anything an AI agent receives. While the connection is open it is held in the app's memory like any other credential; disconnecting drops the app's references to it, but memory is not securely wiped. A read-only connection stays read-only.

Test connection tells you what each credential can do

Test connection runs one probe per ticked service, using the least-privileged request that credential allows — a listing where the token permits listing, service properties where it does not, or a single object for a scoped SAS. After a Microsoft Entra or account-SAS listing it also reads one blob page, one entity or one peeked message from the first container, table or queue, because a listing alone does not prove the data can be read. If the first one is refused, up to 49 more listed ones are read, ten at a time, until one is readable, since a data role can be assigned on single containers, tables or queues. Each row names what was read and how many items were checked, so it never claims more than it checked. Changing a field that the test depends on (the identity, the key, Data access, the services and so on) hides the result until you run Test connection again, and a result never carries over to another connection; the connection name and color do not hide it. A result that arrives after you edited the account or credentials is not shown and unticks nothing. The results keep a readable height below the form (the form scrolls instead), long ones scroll inside their own area, and the dialog's buttons stay on screen. One line above the rows sums up the test, for example Blob verified · Table and Queue refused; when nothing was verified it says so and asks you to fix a service and test again, and Save anyway keeps the connection untested, as after any failed test. It is not offered when the test refused the settings themselves, for example a storage account resource ID that names another account, or an endpoint the account key is not read for; the strip says what to correct instead, and the field it is about scrolls into view. Each row starts with a chip that carries the service and its status. A refused row leads with what the refusal means and what to do in this dialog, such as assigning a role or choosing Single resource under Connect using, and keeps Azure's own sentence under Details. When a single resource refuses its data to a Microsoft Entra identity, the row names the data role (for example Storage Table Data Reader) on that container, table, queue or share, or on the storage account; Reader alone never reads data. When a SAS is refused, the row names the permission it lacks (and, for an account SAS, the resource type), or the service it does not cover. A refusal that no permission fixes names its own cause instead: a SAS whose allowed IP range leaves out your computer (use a SAS whose range includes your public IP address, or one without a range, and check the storage account's firewall; when Azure answers only AuthorizationFailure, which a firewall or disabled public network access also answers, the row asks you to check both the SAS's IP range and the account's Networking settings), an HTTPS-only SAS sent to an http:// endpoint, a storage account that disallows Shared Key authorization (the account key and every SAS signed with it are refused; sign in with Microsoft Entra ID, or for Blob use a user delegation SAS), or a firewall or network rule that blocks your address (for a Microsoft Entra identity, possibly a condition on its role assignment). Each service gets its own row:

  • Verified — the service answered and, where a data check applies, the named item's data was read (“listed containers · listed blobs in container "images"”).
  • Listed, data access not checked (grey) — the account has no container, table or queue to read yet.
  • Partial data access (amber) — some checked items were readable and others refused (“listed blobs in 1 of the account's 6 containers”): the identity's data role covers specific items only. The Object Explorer folder shows a partial data access badge.
  • Listed, but no data access (amber) — the identity lists but every item of the account was checked and refused; the row names the missing data role and how many items were checked, and the folder shows a no data access badge whose tooltip repeats the row. For a SAS the row names the SAS permission that is missing instead of a role. The connection can still be saved.
  • Data access unknown (amber) — the account has more containers, tables or queues than the 50 that were checked, and every checked one was refused. The row says that access to the others is unknown, and the folder shows a data access unknown badge instead of no data access.
  • Failed — the row shows the service's own error, and a 403 names the role or SAS permission that is missing. An account SAS that leaves a service out of its allowed services (ss) says which service; untick it or use a SAS that includes it.
  • Not verified — the credential carries no permission this probe can use (a scoped SAS, for example). The service stays ticked and is tried for real when you open its folder. An account SAS or a Microsoft Entra sign-in that cannot list containers, queues or tables says so and offers Add container names (or queue / table names), which moves to the Open by name row of the form (see Open containers, queues and tables by name).
  • Host not found (grey) — the service's address does not resolve while another service of the same account answered. Usually the account type has no such service: a premium FileStorage account has no Blob, Table or Queue service, so Azure publishes no address for them. It can also be this computer's DNS, for example split-horizon or private-endpoint DNS that resolves only some of the account's services. The row names both causes (No Blob host was found for this account: either the account type has no Blob service, or this computer's DNS cannot resolve it. If the account has no Blob service, untick Blob under Services.) and keeps the DNS answer under Details; the summary line lists these services apart (File verified · Blob, Table and Queue hosts not found (account type or DNS)), they do not count as failures, and the Object Explorer shows no folder for them. Jam SQL Studio concludes this only for the account's own default address (<account>.blob.core.windows.net and so on) and only when another service of the account answered. An endpoint you entered yourself (under Advanced, or as BlobEndpoint, QueueEndpoint and so on in a pasted connection string) and an endpoint suffix other than core.windows.net keep their network error, so a mistyped or custom endpoint is never hidden. When no service answers, every row keeps its network error, because the account name is then more likely mistyped.

Because the probes are per service, a credential that can read blobs but not queues still connects: the connection opens, the blob folder appears, and the services that could not be verified are listed with their reason. If nothing could be verified at all, the connection fails once with the collected reasons instead of a generic error.

The Test connection result for an Azure Storage connection signed in with a shared access signature that covers Blob and Queue only: Blob and Queue verified with the container and queue each one read, Table and File refused because the SAS does not cover them, and those two services unticked under Services.
One row per service: what was verified and what it read, and what failed and why.

Browse containers and blobs

A connected storage account shows a Blob Containers folder in the Object Explorer (named Data Lake Containers when the account has a hierarchical namespace). Expand it to list containers; double-click one to open the storage browser tab. A read-only connection (Access → Open read-only in the connection form) shows a read-only marker next to its name in the Object Explorer and on its Home card, and in the toolbar of each of its storage tabs (next to the location in the storage browser). Rows such as Create container… are actions, shown muted with a plus sign; a name too long for the row ends in an ellipsis and shows in full on hover.

Click a column header in the storage browser to sort the rows it has loaded. Names and other text sort the way Finder and File Explorer sort them: numbers inside a name by value (file2 before file10) and upper and lower case together. Empty cells, such as a folder's size, come first in ascending order and last in descending order. Rows loaded later, as you scroll or with Load all, join the same order.

On the Home page, a connected storage account's card offers one button per service folder (Blob Containers, Tables, Queues, File Shares), which opens that folder in the Object Explorer and lists its contents, plus Transfers, Copy URL (the endpoint, without any key or SAS) and Connection info. A long button label wraps onto a second line. The card's second line names the account and how the connection signs in, followed by the read-only marker and the connection type, so the connection name keeps the full width of the card's first line.

  • Folders and blobs — the browser lists blob name, size, last modified, access tier and type, folders first. The Name column takes the free width, the type reads as a word (Folder, Block blob, Append blob, Page blob, Snapshot, Version; File in the Data Lake view and on file shares), a Status column appears once a listed item has one (deleted, rehydrating, or a new folder that is still empty), and a Lease column once an item is leased (see Leases). Virtual folders (the / segments of blob names) open like directories; the breadcrumb walks back up, and Backspace goes up one level. The breadcrumb always shows the container and the current folder in full, and as many of the folders between them as fit (at most the parent on a deep path); the rest fold into a … menu. Short folder names such as 09 are never cut. Hover a folder, or move the keyboard focus to it, for its full path, and use the copy button at the end of the breadcrumb to copy the current path. The toolbar keeps the same two rows everywhere: the location (breadcrumb, prefix filter, Hierarchy / Flat, and in the Data Lake view the button that opens the other view), and the actions in one order (Upload, New folder, Download, Properties, then the location's own actions and the … menu), with Show, Refresh and copy / export on the right. When the tab is too narrow for every action, the less frequent ones move into the … menu (Show first, then Snapshots…, Download folder, Properties, New folder and Download); Upload, Refresh and copy / export always stay in the row, and the row never scrolls sideways. An action that is unavailable stays visible, and hovering or focusing it shows why. The Last modified column shows the date and time in full; hover it for the exact time in UTC.
  • Hierarchy or Flat — switch between folder-by-folder browsing and a flat listing of everything under the current prefix. In Flat mode each row shows the blob's full path, so blobs with the same name in different folders stay apart. File shares list one folder at a time and have no Flat mode.
  • Selection — the selection belongs to the items you selected. Opening a folder, Refresh, the prefix filter or switching Hierarchy / Flat leaves nothing selected, so an action never reaches a row that appeared in the same place.
  • Empty containers — an empty container, share or folder says which it is, and shows where you can drop files when the connection allows uploads.
  • Prefix filter — Cmd/Ctrl+F focuses the filter box; type a prefix to narrow the listing at the service, not in the grid.
  • Paging — listings arrive 5,000 items per page, the next page loads as you scroll near the end, and Load all in the status bar fetches the rest. There is no total count: Azure's blob API pages with continuation tokens and reports no row total.
  • Copy and export — select rows and copy them as CSV, Markdown or rich text, or export the loaded listing, from the same copy/export menu the query results grid uses. Copy → URL and Copy → Path on the row menu give you a SAS-free URL or the blob's path. The row menu is grouped: open, properties and download first, then tier, SAS and the Data Lake actions, then Copy, and Delete… last. A folder row opens with Open (Enter); a file row's first item is Properties (Enter). The toolbar's Export menu marks each format with the scope it exports, Loaded items. Items that are unavailable stay in the menu, muted, with the reason under their name in readable text, and the toolbar's … menu works from the keyboard like any other menu.
  • Pin a container — right-click it in the Object Explorer and pick Pin to top; Open in Azure portal appears when the connection came from Browse Azure.
The storage browser tab on the images container listing two virtual folders above block blobs with their size, last modified time, tier, type and lease status, with the breadcrumb, prefix filter and Hierarchy/Flat switch on the first toolbar row, Upload, New folder, Download, Properties and the … menu on the second, and a status bar reading 5,000 loaded, more available, with a Load all button.
The storage browser: breadcrumb, prefix filter, hierarchy or flat listing, and paged loading: scroll for the next page, or Load all.

Keyboard

The same keys work in a file share, a share folder and a share snapshot.

ActionmacOSWindows/Linux
Move to and select the next or previous row↓ / ↑↓ / ↑
Extend the selectionShift+↓ / Shift+↑Shift+↓ / Shift+↑
First or last loaded rowHome / EndHome / End
Add or remove the current rowSpaceSpace
Open the row menuShift+F10Shift+F10 or the Menu key
Open the selected folderEnterEnter
Go up one levelBackspaceBackspace
Copy the selectionCmd+CCtrl+C
Copy names onlyCmd+Shift+CCtrl+Shift+C
Cut blobs or folders, to move them with the next Paste (blob containers and Data Lake)Cmd+XCtrl+X
Paste copied blobs or folders here (blob containers and Data Lake)Cmd+VCtrl+V
Rename the selected blob or folder (Blob view; the Data Lake view uses its own rename)F2F2
Select every loaded rowCmd+ACtrl+A
Focus the prefix filterCmd+FCtrl+F
Save the file you are editing in the previewCmd+SCtrl+S

Find blobs and files by name

Azure filters names only by prefix. Find on the storage browser toolbar searches names anywhere under a location, in a blob container, a Data Lake container and a file share. It opens a search bar above the grid:

TypeFinds
invoiceNames that contain invoice
*.csv, report-202?.jsonNames that match as a whole: * stands for any characters, ? for one character
reports/2026/*.csvA pattern with / is matched against the path below the search folder instead of the name; * also matches / there
\*, \?A literal * or ?
  • Match case — the Aa button. Without it, case is ignored.
  • Scope — This folder and subfolders, or the whole container or share. The prefix filter in the toolbar still applies when you search from the current folder. A connection scoped to one folder never searches above that folder.
  • Folders match too: Data Lake and file-share directories, and the virtual folders of a flat container.
  • Deleted blobs — in a Blob view that shows soft-deleted blobs or blobs without a current version (the clock button, see Show deleted blobs), Find searches those too. A deleted match reads deleted · N days left and can be undeleted from its row menu. Changing the view ends the search.
  • Progress — the bar shows how many items were scanned and how many matched. Stop pauses the scan and Continue resumes it where it stopped. The grid shows the first 1,000 matches; Load more shows the next 1,000, and asks first once 50,000 matches are shown. If a request fails, the matches found so far stay on screen with Retry.
  • Results are listed with their full paths. Every row action works on them as in the listing: download, properties, preview, delete, tier, SAS, copy and export, and the Data Lake rename, move and access actions. Double-click a folder to open it. When something in the container changes after the search ran, the bar says so and offers Search again. Navigating, changing the prefix filter or the view, or closing the bar ends the search. After the connection is re-established the results are cleared and the bar offers to search again. The search text is not saved with the session.

What a search costs. Blob containers and Data Lake list up to 5,000 names per request, so a million blobs take about 200 requests. File shares have no recursive listing: Find lists one folder per request, eight folders at a time, so a share with 10,000 folders needs at least 10,000 requests. Each request is a billed read transaction. A name pattern such as *.csv has to scan everything under the scope; start from a deeper folder or set the prefix filter to make it shorter. With Match case on, a path pattern such as reports/2026/* also sends reports/2026/ to the service, which lists only that part.

Find matches blob names. A blob’s earlier versions and snapshots are not listed as separate matches; open Manage history on the blob for those.

Preview and edit files

Click Preview on the storage browser's toolbar to open a pane on the right of the list. It shows the file you select — a blob, a Data Lake file or a file in a file share — and follows the selection as you click rows or move with ↑ and ↓; while the next file loads, the previous one stays on screen, dimmed. Drag the divider between the list and the pane to resize it (← / → when the divider has focus, double-click to go back to the default width). The width, and whether the pane is open, are remembered. In a narrow window the pane sits under the list instead, and the divider sets its height. Click Preview again or the pane's close button to hide it. On a blob or Data Lake tab, the Properties panel takes the pane's place while it is open.

  • JSON — Tree, Formatted and Raw, the same three views as a JSON cell in the query results grid. Formatted keeps every number and escape exactly as stored. The tree is available for valid JSON up to 2 MB, 20,000 values and 100 levels; numbers too large for JavaScript are shown rounded in the tree (Formatted and Raw show them exactly). A file that does not parse opens in Raw with the parser's message above it.
  • Markdown — Rendered or Source. Links open in your browser.
  • Other text — XML, YAML, CSV, logs, configuration files, HTML, CSS, scripts and code open in the editor with syntax highlighting chosen by the file extension; Wrap turns soft wrapping of long lines on or off (off by default, so log and CSV columns line up). HTML is shown as source and never rendered.
  • Images, video and audio — PNG, JPEG, GIF, WebP, BMP, ICO, AVIF and SVG images (Fit or Actual size, with the image's dimensions; an SVG also has a Source view, and scripts inside it never run), MP4, WebM and Ogg video, MP3, WAV, Ogg, AAC, FLAC and M4A audio.
  • Size limits — text up to 5 MB loads whole. A larger text file shows its first 512 KB, read-only, with Load whole file for files up to 32 MB. Images preview up to 32 MB, video and audio up to 64 MB; a larger file offers Download. PDF documents are not previewed in the app: the pane offers Download. A blob stored with a Content-Encoding (gzip, deflate or Brotli) is shown decompressed, read-only.
  • Other files — binary data without a viewer shows the file's size and type with Download and Show as text. A blob in the Archive tier cannot be read until it is rehydrated to the Hot or Cool tier. Selecting a folder or several items says so instead of previewing.
The storage browser with the file preview pane open on the right: appsettings.json selected in the list, its JSON shown as an expandable tree with Tree, Formatted and Raw views, and Edit, Download and Close in the pane header.
Select a file and the pane shows it; JSON opens as a tree, formatted text or the file as stored.

Edit and save

Text files have Edit in the pane's header. While you edit, a bar above the content reads Editing (unsaved changes once you change something) and holds Save (Cmd/Ctrl+S in the editor), Save a copy… and Cancel. Every view edits the same text: typing in Formatted keeps the formatted text, and Raw is the file as stored. The tree can edit a file only when saving from it would change nothing but the edited value, so a file with numbers too large for JavaScript, or with spacing, key order or number spellings the tree would rewrite, opens in Formatted, and its tree is read-only with the reason above it. A file is saved in the encoding it was read in: UTF-8 or UTF-16, with or without a byte order mark; other 8-bit text is shown read-only. The pane stays on the file you are editing when you select other rows. Cancel, closing the pane, closing the tab and disconnecting ask before unsaved changes are discarded. If you quit the app while editing, unsaved changes (up to about 1 MB in all) come back with their tab when you reopen it, and Save still checks that the file has not changed in Azure since you opened it; larger edits are not kept, and the edit bar says so.

  • Save replaces the file only if it has not changed in Azure since you opened it. If it has, or it was deleted, the pane says so and offers Reload (discard your edits and show what is stored now), Save a copy… and Overwrite.
  • Save a copy… writes your text under a new name, in the same or another container (or file share) and folder. The dialog spells out the full path before anything is written and refuses a name that is already taken. A copy beside the original (same container or share) is where editing continues; a copy saved to another container or share ends the edit, so open it there to keep editing. The original keeps what it stores.
  • What a save keeps — a blob keeps its content type and the other HTTP headers, its metadata, its blob index tags and an access tier that was set explicitly. A Data Lake file keeps its owner, group, permissions and ACL. A file in a file share keeps its properties and permissions. A Data Lake file or a file in a file share is saved through a hidden temporary copy next to it; if that copy cannot be removed afterwards, the pane names it so you can delete it. When the connection cannot read a blob's index tags (for example a SAS without the tag permission), Save asks first, because saving would remove any tags the blob has.
  • When Edit is unavailable, hover or focus it to see why: a read-only connection, a SAS or role without write access, a share snapshot, an append or page blob, a compressed blob, or a file that is only partly loaded. A SAS that can create but not write (Create without Write) can only save copies: Save says why, and Save a copy works.
The preview pane in edit mode: the edit bar reads Editing, unsaved changes, with Cancel, Save a copy and Save, above the formatted JSON being edited.
Edit a text file in place, then Save over it or Save a copy.
The preview pane after Save found that appsettings.json changed in Azure since it was opened: a notice with Reload, Save a copy and Overwrite above the edited JSON.
If the file changed in Azure after you opened it, Save stops and you choose Reload, Save a copy or Overwrite.

Browse and edit Table entities

Expand Tables in the Object Explorer to list an account's tables. A table can be opened or pinned like a container. Account-level connections can also create a table, from the Tables folder's Create table… row or from More on a table's tab (Enter in the name field creates it); deleting one requires typing its exact name because the operation permanently removes every entity. A table name that is already taken is refused; names are not case-sensitive, so orders collides with Orders. If creating or deleting a table is refused (read-only connection, missing permission, network), the dialog shows the reason and stays open. Creating and deleting tables needs its own permission (Microsoft.Storage/storageAccounts/tableServices/tables/write and …/tables/delete, part of Storage Table Data Contributor, Storage Account Contributor and Contributor), separate from reading entities. Delete can be granted on a single table; create needs the storage account or its table service, because a new table has no scope of its own yet. With a SAS, creating a table needs an account SAS with the Container resource type and the Create or Write permission, and deleting one needs the Container resource type and the Delete permission; a table's own SAS can do neither. The dialog and the unavailable menu items name the requirement that applies to your connection. Once Azure refuses a create for a missing permission, Create table stays unavailable with that reason until you reconnect; a refused delete makes Delete table unavailable for that table only, in the Object Explorer (the next time its menu opens) and in More on its tab. The Create dialogs name the storage account and connection they create in. A refusal that is not about permissions, for example a SAS whose allowed IP range leaves out your current address or a storage account that disallows Shared Key authorization, shows Azure's reason in the dialog and leaves both actions available, so you can try again as soon as the cause is fixed. A connection scoped to one table exposes only that table.

  • Typed values — each property keeps its Azure EDM type. Large Int64 values stay exact, an integer-valued Double remains a Double, and binary, GUID and seven-digit datetime values are not flattened or truncated. The Timestamp and other DateTime cells show your local date and time, the same format as the rest of the storage views; the exact value is the cell's tooltip, and copy and export keep it. To see UTC instead, tick Show times in UTC under More on any storage tab: entity, queue message, blob and file times, the properties panel, the preview header and the Transfers list then show the UTC value with every fraction digit Azure stores (2026-09-26 22:35:34.2685372 UTC). The choice is remembered and applies to every storage view; SQL result grids are not affected. The special Double values NaN, Infinity and -Infinity are shown, edited and exported as that text. A missing property displays as ∅; an empty string remains an empty string.
  • Filter chips or raw OData — build filters with the familiar filter controls or enter OData directly. Both modes use the same validator, with a maximum of 15 comparisons. Binary OData literals use hexadecimal, such as binary'010203'; entity values remain base64 at the IPC boundary. Raw text stays saved, and Convert to chips keeps the EDM type of every literal, so Count eq 5, Count eq 5.0 and a GUID literal each stay what they are. A raw filter is checked for its own syntax, not against the types seen on the current page: Metric gt 1.5 is accepted even when the first loaded entity stores Metric as Int32. Numbers are sent as plain decimals, so 1e21 goes out as 1000000000000000000000.0. Infinite Doubles can be filtered: type Infinity or -Infinity in a chip, or INF / -INF in raw OData. Azure Table never matches NaN with a comparison, so a NaN value is refused with a hint: a stored NaN sorts above INF, and Metric gt INF finds exactly those entities. While you edit a chip value, the text stays as you type it; a value that does not fit the chip's type, such as - or an empty number, is not applied and the reason is shown under the field. Switching between Filter chips and Raw OData never changes which filter is active: a raw filter the chips cannot show keeps the Filter chips button disabled with the reason next to it. Filters are restored with the tab when a session reopens, each chip value with its EDM type — exact Int64, Int32 versus Double, GUID versus text, seven-digit datetime — so the reopened tab sends the same filter before any page has loaded.
  • Projection, column order and sorting — choose columns to send an Azure $select. Drag a column header, or reorder the Columns menu, to change the column order; reordering sends no request, keeps the current page and is saved with the tab. Clicking a header sorts the page already loaded, by type: numbers by value (Int64 exactly), dates by their full precision, text by character code. Sort all… on the toolbar reads every entity that matches the current filter first (up to 100,000 entities and 128 MiB of data, with Cancel while it reads) and then sorts all of them; the footer says how many entities are sorted and by which column. The sorted view is read-only: Back to pages returns to the pages, and when the table changes elsewhere a banner offers Reload all. A table larger than the limit is refused with the count read so far.
  • Duplicate an entity — in Edit Mode, select an entity and choose Duplicate RowKey… above the grid. Enter the new PartitionKey and RowKey; the copy gets every property with its type as a new row that you can edit before Save. When the view shows only some columns, the full entity is read first, so no property is lost. A key that the table already uses is refused, never overwritten.
  • Continuation paging — choose 100, 250, 500 or 1,000 entities per request. Next follows Azure's continuation handle and always reads the page again, also after going back; Previous uses only cached pages. Azure reports no total, so the footer says how many rows are on the current page instead of inventing a page count; Count on the toolbar counts the table when you ask (see Count entities). After any change saved on the connection, the current page is read again and the pages visited earlier are dropped: past page 1, the footer says Previous page no longer available and First returns to page 1. Refresh, First, a filter, column or page-size change and a reconnect start again on page 1 with no notice, and First is disabled on page 1. When a continuation handle expires (10 minutes idle), the grid shows the expiry and Retry reloads page 1.
  • Draft edits with ETags — turn on Edit Mode, then add entities and typed properties, edit values, remove properties or delete entities, and save the drafts together. As for a SQL table, Add Row, Save and Discard sit in the toolbar; above the grid, Add property to, Remove property… (a menu of the entity's properties) and Delete entity name the selected entity by its RowKey, outline its row in the grid, and wait for a selected row. The Add entity and Add property dialogs label every field and add on Enter. Leaving Edit Mode with unsaved drafts asks whether to save or discard them; while a save is running, leaving Edit Mode waits for it, and if the save fails you stay in Edit Mode with your drafts. Until you save, the grid shows each draft: edited cells carry the pending marker, a removed property shows ∅, a new entity appears as an added row you can remove, and a deleted entity is struck through until you undo it. Each cell is edited according to its own EDM type, so a text value in a column where another entity holds a number or a Boolean is still edited as text. Text that does not fit the cell's type, such as 12a in an Int64 cell or 1.5 in an Int32 cell, is not applied: the editor stays open and shows the reason under the cell. This also applies to values typed or picked in the related-row and enum editors. Clearing a cell and pressing Enter removes that property from the entity (the cell shows a pending ∅), for every type — it never stores 0. Clearing a value you added and have not saved yet only takes the addition back, and a cleared property of a new entity can be typed in again. To store an empty string, use Add property with the type String and an empty value. Typing into a ∅ cell adds the property with the type shown in the column header. Save reports progress partition by partition, then says how many changes were saved and how many are kept as drafts, followed by the entities that changed on the server and those kept for another reason, with the reason (for example 1 change saved; 2 changes kept as drafts. SO-10416 changed on the server. SO-10417 not saved: The entity is larger than 1 MiB.); the line clears when you start a new change. Save stays on the current page and reads it again once, and editing is paused until it finishes. If the connection drops after changes were sent, the status line says they may have been applied, the rows are read again, and the drafts stay so you can check them before saving again. A new entity from such a Save is marked as possibly existing (a dashed outline on its row and a note above the grid); if the reloaded rows contain it, the grid shows it once, as your draft, and your edits go to that draft. The next Save reads the entity first: if it is not in the table, it is added as usual; if it is, your new entity becomes an edit of the stored entity with your values, and the Save after that writes it only if the entity has not changed again. That edit keeps every property of the stored entity that you did not set, such as one another user added in the meantime; it removes a property only if you cleared it in your new entity. The grid shows the stored entity with your changes for you to check, even when it is not on the current page or your filter excludes it, and it can be edited like any other row. An entity over Azure's limits — more than 252 properties, a text or binary value over 64 KiB, or more than 1 MiB in total — is kept as a draft with the reason in the status line while the other drafts save. A changed property on a fully loaded entity is checked against the entity it would produce, so adding a 253rd property is refused the same way. Concurrent changes open a comparison table — one row per property with the server's current value, what Overwrite anyway would write (a property your draft removes reads removed; a deleted entity says the overwrite deletes it) and the original value, the changed cells tinted; long values wrap inside their column, the property names stay in view, and on a narrow window the original values are behind Show original values — with Reload, Overwrite anyway and Keep draft; Overwrite anyway replaces only the version you reviewed, so if the entity changes again first, the comparison reopens with the newer version. On a read-only connection, hovering or focusing Edit Mode shows why editing is unavailable, as for a SQL table without a primary key.
  • Three honest export scopes — one export menu lists Selected rows (every row in the grid selection: Ctrl/Cmd-click adds rows, Shift-click adds a range), Loaded rows and All matching rows, each with Excel, CSV and JSON. A property an entity does not have is left out of that entity's JSON object in every scope, never written as null; CSV and Excel leave its cell empty. JSON keeps native scalar shapes and late properties; CSV/Excel keep the observed column order and report late values they could not include. All matching runs as a background entity transfer that can be cancelled or restarted, never resumed; it reads each page with the same retries and timeouts as browsing, and it stops if the connection is reconnected while it runs. Include type annotations at the top of the menu writes the types too (see Export with types).
  • Storage MetaInfo — declare enum, JSON and loose relationships from property headers. A relationship lookup must identify both PartitionKey and RowKey (the other key is a target filter such as RowKey = region); labels and Open use a point read, never a scan or SQL query, and labels are read again after a change is saved or the connection reconnects. A relationship without that key filter shows the reason in its popover, and Open is unavailable there. In edit mode, a relationship property opens the row picker on the referenced table (search matches the label and key) and a lookup enum opens its labelled value list; the picked key keeps the property's EDM type.

Download blobs and folders

Select a blob, a folder or several loaded rows and click Download. There is no single Download all button for a container yet: press Cmd/Ctrl+A to select every loaded row (use Load all first in a large container), then Download. One blob uses the normal save dialog; folder and multi-item downloads use one folder picker. Each selected folder gets its own safe subfolder, each directly selected blob is saved as a file in the chosen folder, overlapping blobs are downloaded once, and same-name folders and files are disambiguated. Several downloads can write into the same folder at the same time; only two downloads writing the same subfolder or file are refused. A folder download (and an AI agent's container download) writes the current version of every blob. A snapshot or earlier version that an AI agent names by its ID gets its own file name, such as report (snapshot 2026-09-24T07-00-00.1234567Z).csv. Jam SQL Studio never lets an agent choose the destination path.

  • A compact transfers chip appears on the left of a status bar at the bottom of the window (the bar is shown only while there are transfers, so it covers nothing), such as 2 transfers · 1 needs attention; hover it for the breakdown by state. Click it to open the Transfers drawer with active and finished sections, item/byte progress, throughput, and attempt count. Each row names the operation (Upload, Download, Delete, Copy; an access-control job names its mode, such as Replace access (recursive)), when it started, and the connection and path it works on; hover the row for the full route. Closing the drawer returns the keyboard focus to what opened it (the chip, the Home card's Transfers button), or to the chip when that is gone. While the transfer list is still being read the drawer says Loading transfers…; if it cannot be read, a notice says so with Azure's or the app's reason and Retry, and a failed refresh keeps the rows already listed and says the list may be out of date. A job's Show N errors and its error list sit inside that job's block, above the line that separates it from the next job.
  • Cancel stops the download and keeps the partial file, so it can be picked up later.
  • Resume continues from where the partial file ends — only the missing bytes are requested. If the blob changed in the meantime, the download restarts from the beginning and the toast says so. When a stopped download cannot continue (its partial file was deleted or changed by another program), Resume stays in the row but unavailable, and hovering or focusing it shows the reason; use Restart.
  • Restart downloads the unfinished blobs again from the first byte; blobs that already finished are not downloaded again.
  • When a transfer's connection was removed, Resume and Restart stay in its row but unavailable, with the reason on hover or focus; the same applies to an upload, delete or access-control job whose connection is now read-only.
  • A transfer belongs to the storage account it started on. If you edit its saved connection to point at a different account, Resume and Restart are refused with The connection now points at a different account than when this job started. Start a new job., and nothing is sent to either account. The same applies to a copy whose source connection now points at a different account.
  • A Reconnect while an upload runs replaces the connection the upload was using: nothing more is sent through it. The file being uploaded fails with The connection was replaced (Reconnect) or closed while this ran, and files of the same job that had not started yet fail with the same reason without anything being sent. Use Show N errors → Retry on a failed block-blob file to continue on the new connection from the blocks it had already staged (only the missing blocks and the final commit are sent), or Restart to send the job again. Both check the connection as it is now, so a connection that became read-only refuses them with the reason. An append or page blob upload stopped this way can only be restarted. Downloads, previews and Open in local app reading at that moment stop with the same reason; retry or restart them on the new connection.
  • Show in folder opens the finished file in your file manager.
  • Clear finished removes finished transfers that have nothing left to resume, restart or clean up. Unfinished transfers stay in the list until you use Discard unfinished…, which asks first and names what it cleans up: it deletes the partial files of unfinished downloads and the staged copies of file-share uploads, and releases the locks a file-share upload still holds on a published file (the file stays). Discarded transfers can no longer be resumed or restarted.
  • A file that another program holds a lease on (for example, an open file on an SMB share) fails with the next step first: retry after that program releases it. Azure's own message stays under Details.

Transfers survive an app restart: unfinished jobs come back as interrupted, with Resume or Restart. Resume first checks each unfinished item against Azure; if one can no longer continue (for example, the blob changed), the job becomes restart-only and the drawer says why. Partial jobs expose failed items for selected Retry and a redacted error report. Settings → Azure Storage controls concurrent jobs, block concurrency, and block size. A new block size applies to uploads that start after the change; a resumed upload keeps the block size it started with. Restarting an upload sends the file as it is on disk at that moment.

Upload, create folders, and delete

Use Upload → Upload files or Upload folder, or drag files and folders from the operating system onto the active blob container or virtual folder. A CSV dropped here is uploaded rather than opened in Data Import. Directory walking and path validation happen in the main process; a blob that already exists pauses the upload for Skip, Keep both or Overwrite, and the prompt shows the existing file's size and last-modified time next to those of the file being uploaded (a download prompt compares the local file with the one being downloaded). Skip is the default button, so pressing Enter never overwrites anything; Keep both uploads the file under the next free numbered name, such as name (2).ext; Do the same for the other conflicts in this upload answers the upload's later conflicts with the same choice; and Cancel upload (or Esc) stops the upload, keeping the files it already sent. When two files in the same upload would get the same blob name, the upload pauses for Skip or Keep both only, and Overwrite is not offered, so one upload never overwrites a file it just sent. An agent upload whose collision policy is Skip skips such a file; Overwrite or Rename gives it the free name (2).ext name. Every blob name starts with the destination folder exactly as it is shown: a destination folder that starts with / or contains //, a backslash, or a . or .. folder name is refused with the reason before anything is uploaded, and a local file whose name would become such a folder name (for example a file named ..\x on macOS or Linux) is skipped and listed in the job.

New folder creates a local pending upload target. A path such as 2026/10 creates both levels, as in the Data Lake view. It is marked pending until an upload creates the real prefix; empty virtual folders are not marker blobs and are not restored with the session. Object Explorer also provides Create container, Upload, and Delete actions. On a read-only connection, Create container… opens its dialog with Create unavailable and the reason, as Create table… and Create queue… do. A connection whose SAS grants neither Write (w) nor Create (c), such as a list-only sp=rl container SAS, cannot upload: Upload, New folder and an empty container's Upload files… say which permission is missing, and an upload that reaches Azure anyway (from an AI agent, for example) fails with the same sentence instead of Azure's. A SAS with Create (c) but not Write (w) uploads new blobs only: Azure refuses overwriting an existing blob with it, and the transfer item says that overwriting needs the Write permission. When Jam SQL Studio does not know the SAS's permissions (a SAS that uses a stored access policy), the item keeps Azure's own error. Cancelling the Create container dialog while it is working stops the request; if the request had already reached Azure, a notice asks you to refresh and check. Container deletion requires you to type the exact name, and a delete confirmation stays open until the delete has started.

Delete copy is deliberately conservative. Jam SQL Studio can read blob soft delete from this adapter and report on/off/unknown (including retention days when on), and deleting a blob also deletes its snapshots (a snapshot or version that an AI agent names by its ID is deleted on its own). The confirmation lists what it deletes and where (the first ten items, then how many more), marks each folder with "and everything under it", and puts the recovery facts in their own block: soft delete, snapshots and versioning, one line each. When soft delete is off or unknown it also says This cannot be undone. Deleting a folder deletes everything under it, including snapshots and the earlier versions the listing returns. On an account with a hierarchical namespace (Data Lake), deleting a folder also removes its directories, so no empty folder is left behind; if the folder's own directory cannot be checked (for example, without permission to read it), the job ends as partial and says the directory may remain. The folder's own directory is deleted only while it is still the directory that was checked; if another program replaced it with a file in the meantime, that item is skipped as changed since it was checked, and the file is not deleted. On an account without a hierarchical namespace, deleting the folder logs/ never touches a separate blob named logs. Container soft delete and versioning are read from Azure Resource Manager when the connection signs in with Microsoft Entra ID without a browser prompt and that identity may read the account; otherwise they are described as unknown and the app does not promise recovery or retained older versions. When blob soft delete is off, the confirmation offers Enable soft delete… (see Snapshots, versions and deleted items).

The Transfers drawer below the documents container: under Active, a running download of catalog-export.bin with its progress bar, bytes, item count, throughput and Cancel; under Finished, with Clear finished, a completed download of price-list.csv with Show in folder.
Uploads, downloads, and deletes run in the background; the Transfers drawer holds progress, recovery actions, and finished work.

Tabs come back when you resume a session

Open storage browser tabs are part of your session: after a restart, resuming the session from the Sessions dialog puts you back in the same container, folder or table (with Always start a new session set, the app opens the start page instead and the saved session stays available from the Sessions button in the toolbar). For a table, filters, raw OData, selected columns and page size return; rows, cursors, selection, local sort and unsaved drafts do not. Closing an entity tab with unsaved drafts does not ask first, the same as a SQL table in Table Explorer, so save or discard drafts before you close the tab or quit. This includes a new entity marked as possibly existing. No tokens or SAS values are saved in the tab.

Azurite and local containers

Pick Emulator (Azurite) for the well-known emulator account on 127.0.0.1:10000–10002. If Azurite is already running in Docker, Detect Local Databases finds the container and fills in its account and published ports. If the container sets the AZURITE_ACCOUNTS environment variable, the detected connection uses the first account and key listed there rather than the default one. A pasted connection string whose BlobEndpoint, QueueEndpoint and TableEndpoint all point at 127.0.0.1, localhost or ::1 with the account in the path (http://127.0.0.1:20000/devstoreaccount1) also selects Emulator (Azurite): it keeps those ports and the account and key, ticks only the services it names, and leaves File shares unavailable, since Azurite has no Files service (a FileEndpoint or EndpointSuffix in it is listed as not used). A string that mixes local and Azure endpoints is read as a Storage account connection. For a compose file, the flags that matter in a container and fixes for the usual connection errors, see Azurite in Docker.

Azurite over HTTPS. Azurite started with --cert and --key serves https://127.0.0.1:10000/devstoreaccount1 with your own certificate. Change the endpoints to https://, then import the certificate authority that signed it (or the server certificate itself) under Settings → Network → Certificates; until then the connection says the certificate is not trusted and names its issuer. No restart is needed, and removing the certificate refuses the next connection again.

Behind a proxy

Every Azure Storage request — listings, uploads and downloads, queues, tables, file shares, Data Lake, and the sign-in and Azure Resource Manager calls behind them — follows Settings → Network. When the proxy cannot be reached, asks for a user name and password, or the service's certificate is not trusted (a TLS-inspecting proxy), the browser names the proxy or the certificate's issuer and offers Open Network settings. A change takes effect on the next request; a running upload or download finishes on its current connection.

AI agents & MCP

Azure Storage connections expose forty-one storage_* tools to MCP-connected agents: the five read/download tools, transfer status, upload, delete and create-container, five queue tools, storage_generate_sas, three Table entity tools, four file-share tools (storage_create_share, storage_set_share_quota, storage_share_snapshots and storage_mount_command), four Data Lake tools (storage_get_acl, storage_set_acl, storage_create_directory and storage_move_path), storage_find, which finds objects by name the way Find does (each call returns at most maxResults matches after scanning at most maxScanned items, and a continuation token continues the same search), storage_lease, which acquires, renews, releases or breaks leases on up to 100 blobs, containers and Data Lake folders — its approval says what the action does and lists every target, a lease the agent acquires is held by the app, and the agent never receives a lease ID — and three history tools (storage_list_history, storage_snapshot and storage_restore; see Snapshots, versions and deleted items); the read, download, upload and delete tools also take file shares, share folders and share files, and Data Lake paths as blobs and folders. storage_upload takes blobOptions for blob destinations (blob type, VHD and VHDX files as page blobs, access tier, index tags); options the connection cannot honour are refused before the approval, which lists them. Open in local app is not available to agents. A recursive storage_set_acl runs as a job in the Transfers drawer that the call waits for, and storage_move_path never overwrites (see Data Lake). Block refuses every one of them on that connection, and storage_transfer_status leaves out its jobs; Read-only refuses writes; Confirm opens a separate, request-correlated storage approval dialog for every write. It asks what the write does (Delete 3 storage items?; an entity batch names each operation with its count, such as Delete 1 table entity and merge 1 table entity?), shows the tool name as detail, marks whether the write removes, changes or adds data, and focuses Deny first. Every approval lists every target the write touches once, in full, in a list you scroll, with a container or share deletion listed first, above a short summary of the consequences. A call can name at most 1,000 items. A file-share write that the app would refuse (a read-only connection, a snapshot, an item outside the connection's scope, an overwrite on an NFS share) is refused before any dialog. Download still asks you for the destination, and current connection scope/read-only policy is checked again after approval. If the agent cancels a download while Jam SQL Studio is still checking the selected blobs for archive status, the check stops, no save dialog or folder picker opens and no transfer starts; the same happens when you close the storage tab during that check. If the agent cancels its request before you approve it, the approval dialog closes and nothing is written. A cancel after approval stops the work that has not been sent yet and cancels a transfer the request started, but changes already made stay: files uploaded or blobs deleted before the cancel are not rolled back. When a cancel lands while a write is in flight, the app cannot know whether Azure applied it, so the result says the outcome is uncertain; refresh the container to see its current state. Queues add storage_list_queues and non-consuming storage_peek_messages; storage_send_message, storage_receive_messages and storage_clear_queue are refused at read-only and open the same approval dialog at Confirm. Receive results carry neither the Azure pop receipt nor the app's receipt handle, and clear reports a count only as approximate.

Two of them, storage_copy and storage_move, copy and move blobs between containers, connections and accounts, and storage_copy_table copies a table (see Copy a table). Seven work on an Azure subscription connection: storage_list_disks and storage_get_disk read; storage_create_disk_snapshot, storage_copy_disk (in the source's region or, with location, another), storage_upload_disk (a fixed VHD file as a new disk; the file is checked before the approval), storage_download_disk and storage_delete_disk ask for approval at Confirm and are refused on a read-only connection. The download approval says that read access to the disk is granted for up to 24 hours and that Jam SQL Studio revokes the access it granted when the download ends (access granted outside the app stays as it is); you then choose where the VHD file is saved. A disk attached to a VM, or one whose access is already granted, is refused before any dialog: an agent never revokes access. No tool returns an access URL.

SAS generation also requires the configured write approval, and the approval names the resource, the SAS kind, each permission in words and the validity window, with a warning first for an account SAS, write or delete permissions, listing, or a token valid for more than seven days; a request that fails validation is refused before anyone is asked. For a SAS under a stored access policy, Jam SQL Studio reads the policy before asking: the approval shows the permissions, start and expiry the token will have, each marked as coming from the policy or set on the token, with the same warnings, and notes that changing or deleting the policy later changes or revokes the token. A policy that cannot be read, does not exist, has already expired, or lacks a permission or expiry the request does not supply is refused without asking. Jam SQL Studio reads the policy again just before signing: if that read finds it changed since you approved, nothing is signed and the agent has to ask again. A change made after that read is not detected and, like any later change to the policy, applies to the token. Agents cannot generate a SAS on a read-only connection or at the Read-only permission level, not even a read or list token; the app's own dialog can still create those on a read-only connection. The full token stays in Jam SQL Studio. The agent receives the enforced permissions, start, expiry, protocol and IP range as separate fields, and the resource URL without any query string. If an agent's SAS arrives while a storage dialog has unsaved changes or a save in progress, it waits behind a notice with View and opens when you close that dialog.

For Tables, storage_query_entities reads one tagged Table entity page and returns an opaque continuation token; its OData filter accepts at most 15 comparisons. storage_write_entities creates, merges, replaces or conditionally deletes entities. Updates and deletes require a concrete ETag, and the tool follows the connection's Block / Read-only / Confirm policy. The Confirm dialog names the table and the operation totals, marks deletes, replaces and batches of more than 20 entities, and lists every targeted entity by PartitionKey and RowKey once, deletes and replaces first. Property values are never shown. Table create/delete stays UI-only. storage_count_entities counts a table's entities, or those matching a filter, by reading every page; maxSeconds bounds it, and an unfinished count says complete: false. storage_copy_table copies a table into a table on the same or another connection after your approval, and creates the target table only when the agent asks for it and you approve (see Copy a table).

For an open entity tab, table_get_snapshot reports filterState with the active raw-or-chip mode and loading state; table_set_filter resets paging and refuses unsupported operators. Blob downloads still go through the app's save dialog — you pick the destination or decline, never the agent.

From a terminal, the same reads are jam-sql storage containers, ls, props, info and download.

What does not apply

Azure Storage is an object store, not a database. On these connections:

  • There is no SQL Query Editor, SQL Table Explorer, notebook or transaction — those entry points are disabled with a reason. Table entities use the storage explorer's typed grid and OData filters, not generated SQL.
  • There is no Schema Compare, Data Compare, Table Designer or Backup & Restore, and the SQL Data Import wizard does not open for a storage connection; files are imported into a Table with Import… instead (see Import a file into a table).
  • There are no databases or schemas to pick — a connection points at an account (or one scoped resource), and the services are folders.

Properties, tiers, container access and SAS

Properties and metadata

Select one blob and choose Properties from the toolbar or row menu, or press Enter. The side panel shows size, blob type, access tier and archive status, ETag, last modified time, the lease state, its duration and who holds it (this app or another client), with a Lease… menu for the lease actions. Metadata, HTTP headers and index tags have separate editors and Save buttons, so each update sends the complete map for only that section. If tags could not be read, the panel says Tags not loaded and disables tag saving rather than replacing unseen values. Azure keeps an archived blob's metadata and HTTP headers read-only, so those editors are disabled until the blob is rehydrated; its index tags stay editable.

Each section is saved against the version it was loaded from. For a blob, Azure applies the write only while the blob still has that version. Azure offers no such check for container metadata, so Jam SQL Studio reads the container right before saving and refuses the save if the container changed since the panel loaded it (any change to its metadata, public access or stored policies counts); a change made in the fraction of a second between that read and the write can still be overwritten. If the panel refreshes while a section has unsaved edits and that section changed on the server, the section says Changed on the server while you were editing · Reload and its Save stays disabled until you reload it; a change to a different section does not block your edit. A duplicate key is marked on its row and blocks Save (metadata keys ignore letter case, tag keys do not). Jam SQL Studio cannot carry a metadata name or index tag key named __proto__ between its window and the connection: typing one is refused with that reason, and an item that already has one shows __proto__ (not shown) in that section, which stays read-only. A save of that section is also refused if the read Jam SQL Studio makes right before the write finds such a key, so a key found by that read is never deleted; for container metadata and index tags, a key that another tool adds after that read can still be deleted by the save. Change such an item with another tool. The Reload button in the panel header re-reads the item and discards unsaved edits.

A save refused because the item changed on the server shows the same alert as an edit that a refresh found out of date: Changed on the server while you were editing, with a Reload button, and the section's Save stays off (also in the unsaved-changes prompt, which says why) until you reload it. If Azure accepted the write but the follow-up read failed, the panel says Saved — could not read it back; reload to see the current values; an interrupted write whose outcome cannot be proved says Outcome unknown — reload to check whether it was saved. Unsaved drafts remain on their current item until you Save or Discard: closing the panel or pressing its Reload button with unsaved changes asks Save, Discard or Cancel, and a reload that fails keeps your edits. Cancel while that Save is running stops it after the write in progress (which cannot be recalled) and keeps the panel open with your edits; Discard waits for that write. When the editors are locked (a read-only connection, an archived blob, a reload in progress), the reason is shown above them. Metadata and index tags are edited in a Key / Value table where each row has its own remove button; a long value wraps in its field. The properties of a file share, a folder or a file open in a dialog with a Close button.

Saving index tags does not change the ETag, so the tag save first checks that the blob's current tags still match the ones the panel loaded, and Azure applies the write only while each of those tags still has its value. If they changed, the save is refused with Reload instead of overwriting the other edit. Azure's condition cannot check for tags it was not given, so a tag key another client adds between that check and the write is not detected.

Access tiers

Change tier… names the blob it changes and offers Hot, Cool, Cold and Archive, each with a line on what it means: Cool, Cold and Archive keep a blob for at least 30, 90 and 180 days (moving or deleting it sooner is charged for the rest), and an archived blob is offline until it is rehydrated, which can take up to 15 hours. Choosing Archive asks you to confirm with those facts before anything changes. Azure decides whether Archive is available for the account and region; when it is not, only that option is disabled with Azure's reason. If the blob's current tier cannot be read, the dialog shows why with Retry and offers no tier until it can. Moving a blob out of Archive also asks for Standard or High rehydrate priority. Archived and rehydrating blobs cannot be downloaded until rehydration completes; on an archived blob the row menu offers Change tier… (rehydrate). If the tier change is accepted but the follow-up read fails, the dialog says Saved · could not re-read with a Reload button.

Public access and stored policies

On a blob container, Set public access level… names the container and chooses Private, Blob only or Container and blobs, each with what it means; Save becomes available once you pick another level. Create container… offers the same three choices. Blob and Container access require a destructive confirmation that names the public exposure. Manage access policies… names the container, table, queue or share and replaces up to five stored identifiers as one set; each policy's permissions are ticked by name, with the Azure letter beside it, and a resource without policies says so. Save policies becomes available once something changed. Removing an identifier revokes every SAS issued under it, and changes can take up to 30 seconds to apply. Adding permissions to an existing identifier or moving its expiry later extends every SAS already issued under it; the dialog says so under that policy. Azure has no version condition for a container's access settings, so Jam SQL Studio reads the container right before saving (and again before a retry after Azure throttles the save) and refuses the save if its version (ETag) changed since the dialog loaded it. The write also carries the only condition Azure accepts here, that the container is unmodified since the last-modified time the dialog loaded; that time has whole-second precision, so a change made in the same second as that read can still be overwritten. After a refused save, a save whose outcome is unknown, or a save whose follow-up read failed, both dialogs keep your changes on screen and turn Save off; Discard changes and reload (or Reload when nothing is pending) loads the current settings.

Tables and queues have stored access policies too. Manage access policies… in a table's or queue's tree menu opens the same dialog with the permissions that resource accepts (a table: Read, Add, Update and Delete; a queue: Read, Add, Update and Process) and no public access level. Azure keeps no version for a table's or queue's policies, and a write of a file share's policies takes no condition, so for these Jam SQL Studio compares them with a fresh read right before each write, including a retry after Azure throttles the save, and refuses the save if they changed (permissions listed in a different order count as unchanged); a change another tool makes between the last check and the write that follows it can still be overwritten. On a read-only connection the dialog opens for viewing only, for containers as well. With Microsoft Entra ID, a container's access settings need the Storage Blob Data Owner role (Storage Blob Data Reader and Contributor do not include them), and table and queue policies need a custom role with the table or queue getAcl / setAcl action, which no built-in Storage Table Data or Storage Queue Data role includes. When the read is refused, the dialog shows a lock with the sentence that says which of these is missing and that the connection can use the account key for data access instead (Use the account key for data access).

Generate a SAS

Get SAS… creates account or service SAS credentials from an Account Key connection and user-delegation SAS credentials for blob containers, blobs and Data Lake paths from Microsoft Entra ID. The dialog opens on a kind the connection can create for the selected item: user delegation on a Microsoft Entra connection, Account at the account level (where service and user-delegation SAS are unavailable). An account SAS works only on the services ticked under Services, which you see before the token is generated: Blob by default, File when the dialog opens from a share or a file or on an account without Blob storage; tick Queue or Table to add them. The result lists the services the token carries. Before you generate, the dialog names the connection and exactly what the token is signed for; an account SAS says that it works on every container, table, queue and file share of the account in the ticked services, with all three resource types. A kind the connection cannot create stays in the list with the reason under it. Service SAS can be ad-hoc or use a stored policy: a container's own, a blob's container's, or a table's or queue's own. Stored-policy mode lists the resource's policies (it says while they load, when there are none, and when the read failed, with Retry) and asks you to choose one before Generate is enabled. When stored-policy mode is unavailable (an account SAS, a Data Lake directory), the reason is written under the Mode choice. The chosen policy's permissions are shown ticked and its dates filled in, locked and marked From policy; when a policy omits permissions or expiry, the dialog asks for only the missing token field. The result shows the SAS URL (hidden until Reveal) with Copy URL beside it, and the query string, connection string and Add as a Jam connection… as secondary actions. A read-only connection can mint only non-mutating permissions; a container policy that allows read and list counts as non-mutating, and a table or queue policy may allow read only. A user-delegation SAS must expire within seven days from now. Start and expiry times are entered in your local time zone; stored-policy dates in Manage access policies… use local time too, and each set date shows the same moment in UTC (with its UTC offset when your time zone is not UTC or the hour repeats). A time the clock skips when daylight saving starts is refused with a message and blocks Generate or Save until you pick a real time. A time that occurs twice when daylight saving ends keeps the UTC offset the field already had (the first occurrence for a new date), and a button next to the field switches to the other occurrence. A virtual folder has no SAS of its own, so Get SAS… is disabled for folder rows and inside a folder; choose the container or a blob instead.

The result starts masked and shows exactly which permissions (by name) and dates the token enforces and whether each value came from the policy or the token. You can copy the URL, query string, or an account-SAS connection string, reveal the token, or choose Add as a Jam connection…. That last action pre-fills New Connection without writing the token to the clipboard or a session.

File shares

A storage account's File Shares folder in the Object Explorer lists its Azure Files shares, SMB and NFS alike, with a quota badge and an NFS badge on NFS shares. Everything goes through the Azure Files REST API: nothing is mounted on your machine and no SMB or NFS client is needed. Double-click a share to open it in the storage browser.

  • Browse — folders open like blob folders, with the breadcrumb, Backspace to go up, the prefix filter and 5,000-item pages. The grid shows name, size, last modified and type; NFS listings carry no modification time, so that column shows —. A share SAS scoped to one folder or one file opens on that folder or file and never goes above it. Find searches a share or a folder and every folder below it; the share is listed one folder per request.
  • Upload — Upload files, Upload folder or a drop onto the grid uploads into the folder you are looking at; missing folders are created, empty folders included. Each file is written under a hidden temporary name next to its destination and then given its final name without replacing a file that appeared there in the meantime; a name that turned out to be taken asks again (Skip, Keep both or Overwrite). A cancelled upload resumes where it stopped unless another client changed the temporary file, in which case it can only restart. A file that can only start over (another client broke its lock, or the local file changed during the upload) shows Retry unavailable with the reason and offers Restart next to it. When you chose Overwrite and the service refuses the final step (for example because another program has the file open), Jam SQL Studio releases its lock on your file at once and keeps the uploaded copy, so Retry finishes without uploading again. Discard unfinished… removes the temporary files of cancelled uploads. When it cannot (the connection was deleted, is read-only, or no longer reaches the share), the transfer row offers Forget…: the confirmation lists each temporary file or lock the upload still holds, with its share and path, and Forget removes only the entry from the list — the files stay until you delete them. On an SMB share a staged copy is still locked by the upload's lease, and Jam SQL Studio cannot release that lease after Forget; the list says so, and the lease has to be broken (for example in the Azure portal) before the copy can be deleted. A connection that is only disconnected shows Connect to clean up instead: connect it, then use Discard unfinished….
  • New folder creates a real directory in the share (unlike a blob folder, which exists only through its blobs).
  • Download — a file downloads through the save dialog, folders and multi-selections through one folder picker. Each downloaded file keeps its last-write time from the share as its local modification time. On NFS shares, symbolic links are listed but not downloaded.
  • Delete — the confirmation lists the first ten items and where they are, says that a folder is deleted with everything inside it, and states how many snapshots the share has; with no snapshot (or an unknown count) it says the delete cannot be undone. Files are deleted first, then folders from the deepest up; a file that fails keeps its folders, and Retry on that file runs them again.
  • Share actions — the share's menu groups Properties, Snapshots… and Quota…, then Get SAS…, Manage access policies… and Copy mount command…, with Delete share… last, in red; an unavailable item says why on a second line. The File Shares folder offers Create share… (name, optional quota, SMB or NFS).

Quota and billing

The quota a share accepts depends on how the account is billed: pay-as-you-go shares take 1–102,400 GiB (1–5,120 GiB on an older account with large file shares turned off), provisioned v1 shares 100–102,400 GiB, and provisioned v2 shares 32–262,144 GiB. On a provisioned account the quota is the size you pay for, and the dialog says so. A provisioned share can be made smaller only once every 24 hours; the dialog shows when the next reduction is allowed. Azure has no condition for a quota change, so right before writing Jam SQL Studio reads the quota again; if it differs from the one the dialog read, nothing is written and Reload shows the current value. A change another client makes between that read and the write is not detected.

Share snapshots

Snapshots… lists a share's snapshots with their local time, creates a new one, opens one, or deletes one. A snapshot opens as its own read-only tab with a banner: you can browse and download from it, and every write is disabled with the reason. Snapshots cover a whole share, so they are managed from a connection to the account or to the share itself; a connection scoped to one folder or one file, or to a single snapshot, cannot list or create them, and neither can a share SAS (listing, creating or deleting snapshots needs the account key, an account SAS or Microsoft Entra ID). Azure Files has no soft delete for individual files: a deleted file can only be restored from a snapshot.

Deleting a share

Delete share… asks you to type the share's name, and states how many snapshots are deleted with it and whether the account's share soft delete lets you restore it (for how many days) from the Azure portal. Right before deleting, Jam SQL Studio counts the snapshots again; if the count differs from the one the dialog showed, nothing is deleted and the dialog asks you to reload. Azure has no condition for this, so on a share that has snapshots, a snapshot created between that count and the delete is deleted with the share. Tabs and pins on the share close once it is deleted.

NFS shares

NFS 4.1 shares live on premium (FileStorage) accounts. Jam SQL Studio treats them like SMB shares with two differences Azure Files imposes over REST: an upload cannot replace an existing file, so a name collision offers only Skip or Keep both (Overwrite is disabled with the reason), and listings carry no modification times. Stored access policies and SAS work on NFS shares.

Signing in with Microsoft Entra ID

Reading and writing files with Microsoft Entra ID needs Storage File Data Privileged Reader (or Contributor for writes) on the storage account or the share. Listing the shares, and reading a share's quota, usage and snapshots, needs a role that can read the storage account, for example Reader; the Storage File Data roles cover only the files inside a share. An identity without it can still work with shares you name: add them in the connection form's optional File shares field (Test connection links to it with Add share names), or use Open share by name… in the File Shares folder; Remove from this connection takes a named share away again. Creating, resizing, snapshotting or deleting shares needs a management role such as Storage Account Contributor (or the account key); Jam SQL Studio attempts them and, when Azure refuses, names that role. The share soft-delete setting and the account's billing model are read from Azure Resource Manager, which needs Reader on the account. An interactive browser sign-in never starts such a read in the background: the soft-delete setting shows as unknown with the reason, and the billing model comes from the first share you open.

Share SAS URLs

A SAS for a whole share (sr=s) covers every folder and file in it, so a URL like …/share/reports/q3 can name a folder or a file. When you paste such a URL, Jam SQL Studio checks the path with the SAS and preselects File or Folder; when the SAS cannot tell (its permissions allow neither reading the path nor listing it), you pick one before you can test or save. A URL that ends with / is always a folder, and a file SAS (sr=f) always a file. Get SAS… creates a SAS for a share or a file, ad hoc or under the share's stored access policy, from an account-key connection. Jam SQL Studio creates user-delegation SAS tokens only for blob containers, blobs and Data Lake paths, so a share or file SAS needs the account key.

Mount commands

Copy mount command… shows commands you can run yourself: Windows (PowerShell), macOS and Linux for an SMB share, Linux for an NFS share. The account key appears only as a <storage-account-key> placeholder, and the notes cover port 445 and the NFS network requirements. Jam SQL Studio never mounts a share.

Data Lake (ADLS Gen2)

A storage account with a hierarchical namespace (Azure Data Lake Storage Gen2) has real directories and POSIX-style access control lists (ACLs) on every file and directory. Jam SQL Studio detects the namespace when it connects: account-key and SAS connections read it from the account information, Microsoft Entra ID connections from a Data Lake request that needs no data role. The Blob folder in the Object Explorer then reads Data Lake Containers and each container (a file system) carries an HNS badge.

Data Lake view and Blob view

Opening a container of such an account shows the Data Lake view: the same storage browser, listing real directories and files with three more columns, Owner, Group and Permissions (for example rwxr-x---+; + means the path has an extended ACL, t or T the sticky bit). Owners and named entries appear as Microsoft Entra object IDs, with the user principal name beside the ID when Azure reports one. Download, upload (toolbar, drag and drop), delete, properties, tiers and blob SAS work from the Data Lake view as they do in the Blob view. The prefix filter works within one directory level. Neither view lists snapshots, versions or deleted blobs yet.

Find works in both views. In the Data Lake view the results keep the Owner, Group and Permissions columns and the Data Lake row actions.

A tab's title says which view it is (it ends in · Data Lake or · Blob), and a button on the location row, Open in Blob view or Open in Data Lake view, opens the other view of the same location in its own tab; switching back moves the Data Lake tab to the location you reached in the Blob view. Opening the container again from the tree returns to the Data Lake tab where you left it. Right-click a container in the tree for Open blob view and Copy abfss:// URI. A change made in either view (a rename, an upload, an access-control job) refreshes the other view without a manual Refresh.

When Jam SQL Studio cannot confirm the hierarchical namespace (for example, a Microsoft Entra identity without any role on the account), containers open in the Blob view. A Data Lake tab restored from an earlier session waits up to 15 seconds for the account check; if the namespace is still not confirmed, the tab says so and offers Open blob view.

Directories, rename and move

New folder in the toolbar creates a folder (a real Data Lake directory) in the current location; a file or folder that already has the name is reported in the dialog and nothing is created. Missing parent folders are created along the way. The app says folder in the Blob, Data Lake and File Shares views alike.

Rename… (or F2) and Move… in a row's context menu use Azure's own rename, so a directory moves with everything under it, also to another file system of the same account. The request never overwrites anything: it is refused when a file or directory already exists at the destination, including one created by someone else after the dialog opened, and when the source changed after Jam SQL Studio read it. In both cases nothing is moved: for a name that is taken, the name field gets the focus so you can type another; for a changed source, Check source again reads it again. The dialog says what it renames and where, such as Renaming file orders.csv in lake/raw/2026. Moving a directory into itself is refused. In the Blob view of such an account, the dialog reads the directory's current version when it opens.

If Azure answers a directory rename with a continuation, part of the directory may already be at the destination; the dialog says so and offers Continue move, and a notice above the grid lists unfinished moves after a restart. Continue sends the rest only while the source is still a directory and the destination holds the part already moved, and only on condition that neither changed since that check; otherwise nothing is sent, the move stays in the notice, and the notice says that Continue sent nothing and offers Check again, which reads both locations again. If a request was sent but no answer arrived (for example, the network dropped), Jam SQL Studio cannot tell whether the move finished and does not send the request again: the notice asks you to check both locations and offers Check again and Dismiss. Check again reads both locations without sending anything; the notice goes away only when they prove that the move finished or that nothing was moved. Azure gives up on a rename request 30 seconds after it arrives, so Check again reports that nothing was moved only a minute after the answer was lost (for a move left from an earlier session, a minute after the app started); until then the move stays in the notice. The minute is measured as time elapsed in the app, so changing the computer's clock does not shorten it. On a read-only connection the notice offers Check again only. With blob soft delete on, deleted files that were inside a renamed directory stay listed under the old path and can be restored only after a directory with the old name exists again.

On a Data Lake row, the row menu's Copy submenu adds the abfss:// URI and the DFS URL to the Blob URL and the plain file-system/path, never with a SAS token.

Access control (ACLs)

Manage access… opens the access-control editor for one file or directory: the owner, the owning group, the permission string, the access entries and, for directories, the default entries, which apply to new files and directories created inside (use Propagate to change existing ones). Add, change or remove named users and groups by object ID and tick read (r), write (w) and execute (x). The Effective column shows what each entry actually grants: named users, named groups and the owning group are limited by the mask. Jam SQL Studio keeps the mask as loaded while you edit entries, so saving never widens what existing entries can do; change the mask with its own checkboxes or Recalculate mask. Add a default ACL copies the owner and other entries into the default scope, and the owning group as the mask limits it today, so new files and directories get no more than the owning group can use now. Before saving, the editor lists every effective-permission change and marks the ones that widen access.

Azure applies the save only while the path still has the version (ETag) the editor loaded, so a path that was replaced or rewritten since then is refused. An ACL change does not change that version, so right before saving (and again before a retry after Azure throttles the save) Jam SQL Studio reads the access control again and compares it with the one the editor loaded; if the owner, owning group or entries differ, nothing is written and the editor offers Reload and shows what changed. Azure has no condition on the access control itself, so a change another client makes between that read and the write is not detected. Changing access control needs the Storage Blob Data Owner role, or being the owning user of the path with execute (x) permission on every directory above it. Changing the owner needs Storage Blob Data Owner; the owning user cannot hand ownership to someone else. A connection that signs with the account key is a super-user: ACLs are not enforced for it and the editor says so.

Propagate access to everything under a directory

Propagate access… on a directory changes the directory and every file and directory under it, as a job in the Transfers panel. Choose Merge these entries into every descendant, Replace every descendant's ACL with this ACL or Remove these named entries from every descendant; Replace and Remove require typing the directory name. A merge that adds or changes a named entry sets that scope's mask explicitly (pre-filled with the directory's mask). That mask is written onto every path under the directory, replacing each path's own mask, so on a path whose mask was narrower the named entries and the owning group gain what that mask blocked; the dialog says so next to the mask. Azure recalculates the mask of every path a Remove touches, so the owning group can gain what the old mask blocked; the dialog warns about it. A merge that changes a scope's entries without setting that scope's mask (for example only other) also makes Azure recalculate the mask on every path, and the dialog says so. When a merge adds the first default entries of a directory, Azure fills in the default owner, owning group and other from the directory's access entries as they were before the change, the owning group from the access mask when there is one. A Replace with access entries only keeps the default entries of directories under it, and default entries have no effect on files. The preview under the entries shows the directory's own ACL exactly as the change leaves it, these completions and mask changes included; paths under it may differ. The typed confirmation of Replace and Remove lists every entry the change applies and these mask and default-entry effects again. The dialog leads with what the change covers, that there is no undo, and what happens to paths that change while the job runs; the Start button stays in view however long the entry list is. Changes read as sentences, such as Other: gains Read (was no access) — access widens. The AI approval of a single-path storage_set_acl describes its change in the same sentences, with the ones that widen access first.

Azure cannot make a recursive change conditional, so the dialog and the confirmation of an AI agent state exactly what is checked; in the dialog these lines are under How Jam SQL checks this change. For a directory lake/raw they read:

  • Checked now: lake/raw is a directory (version 0x8DE2A1B3).
  • Jam SQL checks it again right before the first batch and stops without sending anything if lake/raw is gone, is no longer a directory or has another version.
  • That check cannot cover the moment between it and the first batch: Azure cannot make a recursive change conditional, so if lake/raw is deleted and re-created in that moment, the change is applied to the new directory and everything under it.
  • Before each later batch Jam SQL checks that lake/raw is still the same directory and stops if it was replaced; a replacement made after a check can still receive that one batch.
  • Files and directories added, removed or changed under lake/raw while the job runs get the change as they are when their batch runs.

A job started on a whole file system cannot notice that the container was deleted and re-created, because Azure reports no creation time for a file-system root; for such a job the dialog and the confirmation say this instead of the per-batch check. There is no undo.

Azure does not change a leased file or folder in a propagation: it lists the path as failed and still changes what is under a leased folder. The failure says which client holds the lease: when it is Jam SQL Studio, Retry applies the change with its lease; when it is another client, Break lease and retry breaks that lease first.

The job applies the change in batches of up to 2,000 paths and records its progress after each batch. Paths Azure refuses are listed in the Transfers panel by path (up to 100; further failures are counted) with Retry for each listed file of a job that finished with failures; once the cause is fixed, a Retry applies the same change to that one path. A failed directory offers Propagate again from this directory, because Azure may have skipped what is under it. When a job is cancelled or interrupted while a batch runs, the panel reports the confirmed counts and says the running batch may have been applied in part and that the remainder is unknown. When Azure ends a job after a batch that changed no path, which is also how it ends a job it cannot continue (for example without permission to read the directory), the panel says how many paths got the change, that the rest of the directory could not be confirmed and why, and that the remainder is unknown; check the permissions and use Restart. Resume continues from the last recorded batch, also after a cancel that came while Jam SQL Studio was checking the directory; Restart runs the whole change again and, for Replace and Remove, asks for the directory name again. The Restart confirmation shows when the job was started and every entry it applies again, since it writes that change over the access control the paths have now.

Directory SAS

Get SAS… on a directory creates a directory SAS that covers only that directory and everything under it (permissions racwdlmeop; a read-only connection can mint read and list only). The result is a DFS URL. On the file-system root the dialog creates a container SAS instead. A user-delegation SAS cannot grant more than the signing identity holds: permissions such as changing ownership or ACLs need Storage Blob Data Owner. Add as a Jam connection… attaches the directory as a connection that shows only that directory. A directory SAS made elsewhere for an account without a hierarchical namespace opens as a Blob prefix.

Leases

A lease locks a blob, a container or a Data Lake folder for one client. While a blob or a Data Lake file is leased, writes and deletes that do not carry the lease ID are refused. A leased container cannot be deleted; the blobs inside stay writable. A leased Data Lake folder cannot be renamed, deleted or given another access control list; the files and folders inside stay writable.

  • Acquire. Row menu → Lease → Acquire lease…, the toolbar's … → Leases (for the selected items, or the open container when nothing is selected), or the Properties panel's Lease… menu. Choose Infinite or 15–60 seconds, and optionally propose a lease ID (a GUID; Generate creates one). An infinite lease stays held after Jam SQL Studio quits, until it is released or broken; a fixed lease ends by itself unless it is renewed. If you quit while the app holds infinite leases, the app asks first: a list of those leases, each with Release, then Quit (whatever is still held stays held) or Cancel. With no window open (macOS), and when an update restarts the app, a system notification lists them instead.
  • The Lease column. A lease the app holds reads Leased · infinite · this app or Leased · 30 s · this app (hover for the time a fixed lease ends); another client's reads Leased · infinite · another client; a lease being broken reads Breaking, then Broken. Azure's Data Lake listing does not report leases, so the Data Lake view shows only the app's own; the Properties panel shows any lease.
  • Writes under the app's lease. Deletes, uploads, the editor's save, metadata, HTTP headers, index tags, the access tier, Data Lake access control and renames send the app's lease ID, so they work on an item the app has leased. A fixed lease on a blob or a Data Lake file is renewed while a long write runs. A fixed lease on a Data Lake folder is not renewed during a write, because every lease request gives the folder a new version and the write is conditioned on the version it was shown; the folder's lease keeps the time it has left, so renew it first before a slow access-control change or rename. A renamed Data Lake folder keeps its lease, and the column follows it to the new name; this also holds when the folder is renamed through another connection to the same account. Create snapshot sends the lease too; a change to a snapshot or an earlier version never does (a lease belongs to the current blob), and Undelete needs no lease.
  • Renew, Release, Change lease ID…, Copy lease ID. These act on leases the app holds. The app keeps lease IDs in memory while it runs: they survive disconnecting and reconnecting the same account, and are never saved to disk, written to logs or given to AI agents. Use a lease ID… takes over a lease created elsewhere: the app checks the ID with Azure and then treats the lease as its own.
  • Break lease… ends any client's lease, at once or after a break period of up to 60 seconds. The client that held it is not told; its next write or delete that uses the lease is refused.
  • Break lease and … When a delete, upload, save, metadata or tier change, access-control change or rename is refused because another client holds the lease, the error offers Break lease and delete (or retry, save, change tier, rename). The confirmation names the item and says that the other client loses its lease. The break happens only if the item is unchanged since your operation read it, and the operation then runs once more on the same condition. In the Transfers panel, Break leases and retry covers every leased item of a job.
  • Several containers. Right-click the Blob containers folder in the tree and choose Container leases…: tick containers in the list (it loads page by page, with a name filter and Load more), then choose Acquire, Renew, Release or Break; the result lists each container. A container's own Lease submenu is on its node in the tree.
  • Uncertain. If the answer to a lease request is lost (for example, the network drops), the column reads Uncertain and writes to that item are refused until you choose Lease → Check, which asks Azure whether the app holds the lease. The same happens to the leases on and under a folder whose rename got no answer, at both the old and the new path.
  • Kept lease IDs. The app never throws a lease ID away. When Check, Renew, Release or Change lease ID finds no lease of the app's on the item (another client moved it, or the lease ended), or when something replaces the app's record of a lease (a new lease acquired at a path whose old item another client moved, a rename onto a path the app had a lease record for, a folder delete), the ID moves to the toolbar's … → Leases → Kept lease IDs…. Each ID is its own row with its old path; when an interrupted request left several possible IDs, the rows say ID 1 of 2, ID 2 of 2 (the first is the most likely). Copy lease ID copies the ID, so you can use it with Use a lease ID… where the item is now. Release… asks where the item is now (the old path is filled in) and releases the lease there with that row's ID; the row goes once the release went through, and stays when Azure says the ID is not the lease in force there. Forget removes a row. A new lease on, or a delete of, whatever now sits at the old path does not touch a kept ID, even when the new lease uses the same proposed ID. Break lease… ends whatever lease is on the item now at the path, so the app keeps the IDs it held there, with the note Lease at <path> was broken; this ID may belong to an item moved elsewhere; only a Release or Change lease ID with that exact ID lets an ID go. On a read-only connection, Release… is disabled.
  • Data Lake folders. Every lease request on a folder gives the folder a new version. A Rename dialog opened before another client leased the folder therefore reports that the folder changed: choose Check source again, rename again, and then Break lease and rename.

Snapshots, versions and deleted items

Azure keeps earlier versions of a blob when versioning is on, snapshots you create, and soft-deleted blobs, containers and file shares for the account's retention period. Jam SQL Studio lists and restores them; everything it shows in these views is read-only until you restore it.

Show deleted blobs

The clock button on the location row of the Blob view picks what the grid lists: Active blobs (the default), Active and soft-deleted blobs, Active blobs and blobs without a current version (a blob whose current version was deleted while earlier versions remain), or All blobs and blobs without a current version. On a Data Lake account the choices are Active, Active and deleted and Deleted only; choosing a deleted view in the Data Lake view opens the Blob view of the same folder. While a deleted view is open, a banner says so, a Version column shows version IDs, and the Status column reads, for example, deleted · 6 days left. A deleted row cannot be opened, renamed, deleted again or signed; its menu offers Undelete. The choice is kept with the tab when you restart.

Manage history

Manage history… on a blob (row menu, or History… on the toolbar) lists its current version, earlier versions and snapshots with their time, size, tier and status. Select entries to Download, Delete, Change tier…, Get SAS… (a SAS for exactly that version or snapshot; it does not open the current blob) or Compare two entries side by side (differing properties and metadata are highlighted). Create snapshot is refused when the blob changed since the dialog read it. Undelete all restores every soft-deleted version and snapshot of the blob; Azure restores them together. An archived snapshot or earlier version cannot be brought back to an online tier in place; Azure only allows copying it to a new blob.

Promote, Restore latest version and Copy to a new blob

Promote… makes the selected version or snapshot the current blob: Azure copies it over the blob server-side, as a job in the Transfers drawer. The confirmation says what happens to the current content. When Jam SQL Studio could read from Azure Resource Manager that versioning is on, the current content becomes an earlier version. Otherwise it is replaced. With blob soft delete on, Azure keeps the replaced content as a soft-deleted snapshot for the retention period, and the confirmation says for how many days it can be undeleted; with soft delete off it is not kept. Either way Snapshot the current blob first is ticked, so a snapshot keeps it. The promote is refused, and nothing is written, when the blob changed after the confirmation opened. A lease the app holds on the blob is used. When another client holds a lease, the confirmation says so and offers Break lease and promote. When a blob has no current version (it was deleted while versioning was on), Restore latest version… copies its newest version back as the current blob, even when Manage history lists only the first part of a long history. When that newest version is archived, nothing is restored and the dialog offers Copy to a new blob… for it instead. Copy to a new blob… copies a version or snapshot to a new name in the same container. An archived one can only be copied this way, to the Hot, Cool or Cold tier, and Azure rehydrates the copy (up to 15 hours at Standard priority).

Undelete

Undelete restores the selected deleted items and, for a selected folder, everything soft-deleted under it (a confirmation says what comes back). Undelete by date… in the More menu restores what was deleted inside a time window, read in your local time or in UTC. Each undelete runs as a job in the Transfers drawer: a failed item can be retried, and the job can be restarted. On a flat account, Azure restores every soft-deleted version and snapshot of a blob together. On a Data Lake account a path can have several deleted copies; selecting a row restores exactly that copy, and a folder restores the most recently deleted copy of each path. A deleted folder is restored before what was inside it; a file whose folder is still deleted is not restored and says so. An item whose name is now used by another file or folder stays deleted and the existing one is not touched. On a read-only connection Undelete is unavailable.

Deleted containers and file shares

Deleted containers… on the Blob Containers folder and Deleted file shares… on the File Shares folder list what the account keeps after a delete, with the time and the days left, and Restore brings one back under its own name with its contents. Azure accepts a restore about 30 seconds after the delete; until then the row says so and offers Retry. A name that a live container or share already uses cannot be restored. Deleted shares are listed for connections that can list shares; with Microsoft Entra ID, restoring a share needs a management role such as Storage Account Contributor.

Soft delete settings

Soft delete settings… on the Blob Containers folder shows and changes how long deleted blobs and deleted containers are kept, and shows whether versioning is on. Blob soft delete works with every sign-in. Container soft delete and versioning are Azure Resource Manager settings: they are shown with a Microsoft Entra ID sign-in that may read the account (with a browser sign-in, after you click Read from Azure), and changed when the identity has a role such as Storage Account Contributor. Before saving, Jam SQL Studio reads each changed setting again and saves nothing if it changed since the dialog opened. If Azure saves one setting but refuses or does not confirm the other, the dialog says which one was saved; reopen it to see the current values. Azure applies a new policy within 30 seconds. When a delete confirmation says soft delete is off, Enable soft delete… opens these settings; while the save runs and for 30 seconds after Azure answers it, the confirmation's Delete waits, so the delete is covered by the new policy.

AI agents

storage_list takes include flags (deleted, versions, snapshots, blobs without a current version), storage_list_containers takes includeDeleted, and storage_list_history lists a blob's versions and snapshots or a Data Lake path's deleted copies; storage_find takes the same include flags (deleted, blobs without a current version) to search them by name. storage_snapshot and storage_restore (undelete, restore a container or a share, promote a version or snapshot) open the approval dialog at Confirm, listing every item they restore. A promote's approval names the entry and says whether the current content is kept as a version or a snapshot; the call waits for the copy job.

Upload with options: blob type, access tier and index tags

In the blob and Data Lake views, Upload → Upload with options… opens a dialog for files and folders (Add files…, Add folder…, or drop them onto the dialog) with the choices a plain upload does not offer:

  • Blob type. Block blob (the default), append blob or page blob. A page blob's size must be a multiple of 512 bytes; a file that is not is listed with the reason and not uploaded. All-zero runs of 64 KiB or more are not sent, so a sparse file such as a disk image uploads only its data and its page ranges list only that data. An append blob is written block by block, up to 100 MiB per block.
  • VHD and VHDX files as page blobs (on by default): those files become page blobs whatever the blob type says, as Azure disks need. A .vhd file that is dynamic or differencing is named in the dialog, because Azure disks need fixed VHDs.
  • Access tier for block blobs: Hot, Cool, Cold or Archive (with a note that an archived blob must be rehydrated before it can be read). Azure does not set a tier on append and page blobs, so the control says so for them.
  • Index tags, up to 10, set on every uploaded blob in the same request.
  • When a blob already exists: Ask, Skip, Keep both or Overwrite. Azure does not replace a blob with one of another type (a page upload over a block blob, for example), so such a file is offered Skip or Keep both, with that reason.

What the connection cannot do is shown on the control with the reason: a Data Lake account (hierarchical namespace) has no page blobs and no index tags; a SAS needs Write (w) for append and page uploads and Tag (t) for index tags. The upload runs as one job in the Transfers drawer. An append or page upload can be cancelled and resumed: while it runs, the app holds a lease on the blob so no other client writes to it, and Resume continues only when the blob is still exactly as the upload left it; otherwise the item can only be restarted. Discard unfinished deletes a partial blob only while it is still the one this upload created, and never a blob that has snapshots. A page or append blob is visible, partially written, while it uploads.

Open in local app

Right-click a blob, a Data Lake file or a file on a file share and choose Open in local app (also in the toolbar's … menu for the selected item). Jam SQL Studio downloads it into a private temporary folder and opens it with the app your computer uses for that kind of file. If the object changes in storage while it downloads, the download starts again, so the copy is always one complete version.

  • Which files open. Documents, data files, images, audio and video open directly. Files that can run a program on this computer (on Windows, for example .exe, .bat, .ps1 or .lnk; on macOS .app, .command or .pkg; on Linux .sh, .desktop or .AppImage) are never opened from storage; download them instead if you trust them. Any other extension asks first: Open once, or Always trust .xyz files. Settings → Azure Storage → Open in local app lists the trusted extensions, where you can remove or add one or go back to the defaults. On Windows, the copy is marked as downloaded from the internet, so Office opens it in Protected View.
  • Changes. When you save the file in the other app, Jam SQL Studio notices it and offers Upload changes or Ignore. For each opened file you can choose When it changes: Ask, Upload automatically or Ignore in Opened files on the toolbar, which lists this connection's opened files with their state, progress and Cancel, and has Upload changes, Save as…, Show in folder, Open again and Close. Settings → Azure Storage can turn watching off; Upload changes still works then.
  • Uploading back. Upload changes replaces the object only if it is still the version you opened, and keeps its metadata, HTTP headers, index tags and access tier (Data Lake files keep their owner, group and access control list). If someone changed it in storage meanwhile, the app asks: Reload (your local changes are discarded and the stored version opens), Keep mine (after a second confirmation, your file replaces the stored one), Save as a new name… (next to the original, with its headers and metadata but not its index tags) or Cancel. If it was deleted, Upload as new creates it again, unless another client has created that name in the meantime. If another client holds a lease on the blob, the error offers Break lease and upload; a lease the app holds is used and stays held. If the connection breaks before Azure answers, Check compares what is stored with what was sent.
  • Open only. On a read-only connection, and for append and page blobs, snapshots, versions, share snapshots and compressed blobs, the file opens but Upload changes is unavailable, with the reason. On an NFS share, Save as a new name is the way back. Block blobs of any size upload back; Data Lake files and files on file shares upload back up to 64 MiB.
  • Closing and quitting. Close in Opened files deletes the local copy (asking first if it has changes that were not uploaded). When you quit with changes that were not uploaded, one prompt lists the files: Upload changes and quit, Discard and quit or Cancel. The temporary copies are deleted when the app quits. If the app closes unexpectedly, the next start offers the copies with changes once (Upload changes, Show in folder or Discard).

Copy, cut and paste blobs and folders

Select blobs and folders in a blob container or a Data Lake file system and press Ctrl+C (Cmd+C on macOS), or choose Copy blob, Copy folder or Copy N items in the row menu. The selection's text still goes to the clipboard as before, and the items are marked for pasting. Open the container or folder that should receive them — on the same connection or another one, in the same storage account or another account — and press Ctrl+V (Cmd+V), click Paste in the toolbar (it appears while items are marked, and its tooltip names what it pastes and from which connection), or choose Paste into folder on a folder row. If you copied anything else since, Paste says so and does nothing.

The paste dialog shows what will happen before anything is written: how many items and bytes, from where to where, items that are not copied and why, and how many blobs already exist at the destination. When some exist, choose Skip them, Overwrite them (only while they are still the blobs that were checked), Keep both (the copy gets a numbered name, such as report (2).csv) or Ask for each (each conflict waits for your answer in the Transfers drawer). The dialog checks the first 1,000 items; for a larger selection it says so and asks for a choice that applies to the items it did not check. A folder cannot be pasted into itself.

Azure copies the data itself, server-side: nothing is downloaded to your computer. A copy keeps the blob's content type and other HTTP headers. Keep the access tier (on by default) gives the copy the tier the original was set to; without it the copy gets the destination account's default tier. Keep metadata is on by default. Keep blob index tags is off by default (reading tags needs the tag permission), and unavailable for a Data Lake destination, which stores no index tags. The paste runs as a Copy job in the Transfers drawer, with Cancel and per-item Retry. Copying between accounts uses a short-lived, read-only signature for each source blob, created when the copy starts; it is never stored.

The source and destination can use different sign-in methods: an account key, Microsoft Entra ID, or a shared access signature (SAS). A connection that signs in with a SAS is read with its own token; if that token expires within the next 48 hours, the paste dialog shows when, because a copy still running at that time fails. A read-only connection can be the source of a copy, but not its destination.

Between a Data Lake file system and a flat blob container: a folder pasted into a Data Lake file system arrives with its subfolders, empty ones included. Pasted into a flat container, its files are copied and its folders are listed as not copied (a flat container has no folders of its own). Page blobs cannot be copied into a Data Lake account. A file and a folder cannot have the same name on a Data Lake account, so such an item fails with that reason, and you can retry it after renaming or removing the other one.

A large blob copied to another account can take a while. The Transfers drawer shows it as running until Azure reports it complete. Cancel stops the copy in Azure and removes the empty blob it created; Resume starts it again. Quitting the app cancels running transfers, copies included. If the app stops unexpectedly while Azure is still copying, Azure carries on: after a restart the job reads Interrupted, and Resume picks up the same copy instead of starting a new one. If a copy request got no answer (for example, the network dropped), the item fails with "it is not known whether the blob was copied". Check the destination, then click Retry. If the blob is there now, you choose what happens to it.

Clone and rename

Clone… in a blob's or folder's row menu copies it to a new name in the same folder; the name starts as report (copy).csv. Rename… (or F2) in the Blob view gives a blob or folder a new name: Azure Storage has no rename for blobs, so the item is copied to the new name and the original is deleted after the copy is checked, as with a move. A folder is renamed blob by blob. If the new name is taken (for a folder: a folder of that name already exists, even with different blobs in it), the dialog says so and nothing is changed. In the Data Lake view, Rename… uses Azure's own rename (see Directories, rename and move).

Copy a whole container

Right-click a container in the tree and choose Copy container, then right-click the Blob Containers folder of the connection that should receive it and choose Paste container. The container is created there with the same name, its blobs and, with Keep metadata, its metadata. Its public access setting is not copied: the new container is private. If a container with that name already exists, choose Merge (copy the blobs into it; the choice for blobs that already exist applies), New name (a new container such as logs-copy) or Skip. A container cannot be cut: copy it, then delete the original. An empty container is created too, with its metadata.

Copy an archived blob

An archived blob can be copied to a new blob in the Hot, Cool or Cold tier. When the selection holds archived blobs, the paste dialog (and Clone… on an archived blob) asks for the tier of the copy and the rehydrate priority: Azure rehydrates the copy within about 15 hours at Standard priority; High priority may finish in under an hour for blobs under 10 GB. The Copy job finishes when Azure accepts the copy, and the Transfers drawer says Rehydrating in Azure; the copy can be read once Azure has rehydrated it. Azure copies an archived blob to another storage account only within the same region; otherwise the item fails with that reason. The copy keeps the source's metadata, so Keep metadata stays on while archived blobs are pasted. Archived blobs cannot be moved or renamed, and a blob that is being rehydrated is not copied.

Move blobs and folders (cut and paste)

To move instead of copy, press Ctrl+X (Cmd+X) or choose Cut in the row menu or in the toolbar's … menu, then paste. The paste dialog says Move. Each blob is copied first; its original is deleted only after the copy is checked at the destination, and only if the original is still the version that was copied. While a move checks its copy and deletes the original, it holds an infinite lease on the copy so nothing else can change it; the lease is released when the move finishes, or when you retry, restart or discard it. If a delete, or a request for that lease, gets no answer and cannot be confirmed, the item says the outcome is unknown and the copy stays leased until you retry or discard the move; Retry checks the lease first and then continues. If the destination connection is read-only when you discard the move, nothing is sent: the lease stays on the copy and the Transfers drawer says why; make the connection writable and discard again. A move onto a blob you hold a fixed-duration lease on is refused before anything is copied, because that lease can end before the original is deleted: release it or acquire an infinite lease, then retry. If Jam SQL Studio closes during that time, the lease remains on the copy and shows as another application's lease in the Lease column, where you can break it. An original that changed after it was copied, has snapshots, or is leased by another application is kept: the copy stays at the destination, and the Transfers drawer says why the original was kept. Moving a Data Lake folder to another account or connection also removes its folders once everything in them has moved; a folder that still holds something is kept. Before a source folder is removed, the destination folder is checked again: if someone deleted it in the meantime it is created again, and if a file now has its name, the source folder is kept.

Within one Data Lake connection, a move renames the files and folders instead of copying them. A rename is immediate and keeps properties, metadata and access control (ACLs). It never replaces an existing path: choose Skip them or Keep both (a numbered name). A message lists what was moved and what stayed. A read-only connection cannot cut. A container cannot be cut either: copy it, then delete the original. Snapshots and earlier versions can be copied but not moved.

Limitations in this release

  • File shares: no soft delete for individual files (only a share snapshot can restore a deleted file); no overwrite on NFS shares; shares are never mounted, mount commands are text for you to run; with Microsoft Entra ID, share management needs a management role such as Storage Account Contributor, or the account key; Jam SQL Studio creates a share or file SAS with the account key only, not as a user-delegation SAS.
  • Data Lake directories are not expanded in the tree. Browse them in the Data Lake view. Deleting a directory deletes its contents path by path (Azure's server-side recursive delete is not used). Deleted Data Lake paths are listed and restored in the Blob view (see Snapshots, versions and deleted items).
  • Open in local app: Data Lake files and files on file shares upload back up to 64 MiB; append and page blobs, snapshots and versions open read-only; Save as a new name does not copy index tags; a page or append blob uploaded with options is visible while it uploads.
  • No total item count. Azure pages blob listings with continuation tokens and reports no total, so the browser shows what is loaded, fetches the next page as you scroll, and offers Load all.
  • Azure Stack Hub: on an environment with the Azure Stack Hub API profile, connections use the account key, a SAS, or the account key read through Resource Manager (not Microsoft Entra data roles); there is no File Shares folder, and access tiers, index tags, versions, soft delete, Data Lake Storage and user delegation SAS are unavailable with the reason. Immutability policies are unavailable in Jam’s Stack profile. SAS permissions that version 2019-07-07 cannot sign are disabled with the reason. Blob names are limited to 880 characters and table keys to 400 (an upload Retry and a table import are held to the same limits). In Upload with options, Tier and Tags are unavailable with the reason, page blobs are written in 4 KiB pages (a page blob’s size must be a multiple of 4 KiB, at most 1 TiB), and append blobs are written in blocks of at most 4 MiB.

Queues

Expand Queues in Object Explorer to see queue names and Azure's approximate message-count badge. Create a queue from the folder menu, the action row, or the empty-folder row. A queue's menu can add a message, clear it, or delete the queue; clear and delete require typing the exact queue name. Clear shows the service's approximate count when available, or says explicitly that the count is unavailable and every message will be removed. If Clear or Delete fails, the confirmation stays open with a visible reason so you can correct the problem and retry.

Open a queue to show its messages in the Table Explorer grid. Peek reads the first visible messages (as many as the number beside it, up to 32) without consuming them; a new count applies when you press Enter or leave the field. Clear queue… is in the toolbar's … menu. The message text is the first column and the message ID the last; times show in the same format as the rest of the storage browser; hovering a time shows the exact value, and copy (including Ctrl+C on a selected cell) and export keep it. When reading messages is refused (a missing data role), the tab keeps the reason on screen until access changes. The grid inherits Table Explorer keyboard selection, copy and export behavior, while SQL actions and editing stay disabled. Decode Base64 changes display and export text only. A queue tab whose connection was removed shows a message with a Close button.

Receive… takes the next messages from the front of the queue, not a selected row, and hides them from other readers for the visibility timeout. A bar above the grid then says how many received messages it shows and until when they stay hidden, with Back to peek. Every seconds field in the queue dialogs also shows its duration in words (604800 = 7 days). Receiving again adds the new messages to the received rows you still hold; rows whose visibility window elapsed drop out. A received row can be updated or deleted while its receipt is current, measured against your computer's clock from the moment the messages arrived; the message's expiry time is measured the same way. Receive again after the visibility window elapses; an expired, replaced or externally deleted receipt cannot be retried from the stale row. When the queue is cleared from any place (the tab toolbar, the Object Explorer menu or an MCP agent), or a received message is deleted elsewhere, open queue tabs drop those received rows on their next refresh. When no received row is left — you deleted the last one, cleared the queue, or a Receive found no visible message — the tab peeks the queue again. Update visibility cannot extend beyond a finite message expiry; the dialog says how long a message can stay hidden, such as up to 6 days 23 hours. When Decode Base64 is on, Update… shows the decoded text and saves it Base64-encoded again (clear Encode as Base64 in the dialog to save plain text). One connection holds at most 200 received messages at a time; delete received messages or wait for their visibility timeout before receiving more.

Read-only connections can list and peek but disable add, receive, update, delete, clear and queue lifecycle controls. A mutation interrupted after dispatch reports an uncertain outcome — peek before retrying. Queue tabs persist only their queue identity and view settings; opaque receipts and message bodies are not written to the session file.

Import a file into a table

A CSV, TSV, JSON, NDJSON or Excel file can be imported into an existing table with Import… on the table's toolbar or Import entities… in its Object Explorer menu, or into a new table with Import into a new table… on the Tables folder. Dropping a data file on a table's tab opens the same dialog with that file. The dialog has three steps:

  1. File — pick the file and check the parsing settings (format, delimiter, header row, encoding, Excel sheet). Cells are imported exactly as written: no value counts as empty unless you add it to Null values, and spaces are kept. The preview shows the type each column's first rows suggest. Next reads the whole file once to type every column; until it has, Browse and the parsing settings are unavailable.
  2. Table and columns — name the new table, and choose where PartitionKey and RowKey come from: a column, a constant, a generated GUID or the row number (0000000001, …). When a key comes from a column, an empty key cell can skip the row and report it, get a generated GUID, or stay empty. Each column can be left out, renamed and given a type: the inferred one (for example Inferred: Int32), any of the eight Azure Table types, or Per value, which types each cell by what it holds. A name Azure Table refuses (a reserved name such as RowKey, a name starting with a digit or containing spaces, or a name used twice) shows the reason with a suggested name, and Next stays unavailable until it is fixed. A file with Name@type or [email protected] columns, such as an export with type annotations or an Azure Storage Explorer export, types each cell by its type column; the switch Use the file's type columns turns that off. Timestamp and OData columns are not imported. A file may have more than 252 property columns: Azure's limit of 252 properties applies to each entity, and an empty cell adds no property, so a row with more than 252 filled cells fails and is reported while the others are written.
  3. Write — choose what happens when an entity with the same PartitionKey and RowKey exists: Insert reports the row and leaves the entity as it is, Upsert – merge adds and updates the file's properties and keeps the others, Upsert – replace replaces the entity with the row. Choose whether an empty cell leaves the property out or stores an empty string (String columns), and whether a failed row is skipped and reported or stops the import.
The Import into CustomersLight dialog on its Table and columns step: PartitionKey and RowKey from the file’s columns, the switch for the file’s type columns, and a column list with Import, Property, Type and sample values; Customer since is typed by its @type column and its name is refused with a suggested name, Customer_since.
The Table and columns step: where the keys come from, a type per column, and a suggested name where Azure refuses one.

Start import runs the import as a job in the Transfers drawer. Until the job has started (a new table is created first), the dialog stays open and Cancel and Back are unavailable. Rows of one partition are written in changesets of up to 100 entities, and several partitions are written at once; each changeset is applied completely or not at all, the import as a whole is not. With Stop at the first failed row, nothing more is sent after a failed row or after a changeset whose answer was lost, but requests already sent may still complete. Generated GUID keys are the same every time the same import runs, so Restart after a cancel or a closed app writes the same entities again instead of adding duplicates. The job lists the rows it could not write with the row number, the column and the reason; Save error report… saves them all as a CSV file (until the app closes). If the connection drops after a changeset was sent, its rows are listed as may have been written and are not sent again on their own. Retry failed rows… and Retry uncertain rows… start a new job for exactly those rows after a confirmation that says what the retry does: with Insert, rows that are now in the table are reported as conflicts; with an upsert, the rows overwrite what the table holds now. A retry always uses the rows of the job's last run; if they could not be saved, or the import ran again after you confirmed, the retry is not started and says why. If the file changed after the import started, Restart and Retry are refused. A read-only connection offers no import, and a connection scoped to one table cannot create a new one.

The Transfers drawer with the import of customers.csv partly completed: 7 of 8 rows written, 1 failed, with Restart, Hide rows, Retry failed rows, Save error report and Open table; row 7 names the column Customer since and why its value is not a DateTime.
An import lists the rows it could not write, with the reason; retry them or save the error report.

An export with type annotations imports back into the same entities: the same keys, property names, types and values.

Export with types

Azure Table storage keeps a type with every value, and a plain CSV or Excel file loses it: an Int64, a GUID or a date reads back as text, and a Double that holds a whole number reads back as an integer. Tick Include type annotations at the top of a table's export menu (the choice is kept until the app restarts) and every scope — Selected rows, Loaded rows and All matching rows — writes the types:

  • CSV and Excel get a Name@type column after every property column, with the type in each cell (Edm.Int64, Edm.Double, Edm.DateTime, …). A property an entity does not have leaves both cells empty; an empty string has an empty value and Edm.String. Every cell is text, so Excel never turns a large number or a date into its own format.
  • JSON is a list of objects in Azure's own payload format: every value is a string with its type beside it in [email protected]. Azure Storage Explorer reads the same format.
  • Every property of every exported entity is written, also the ones the tab’s Columns choice hides: All matching rows reads complete entities, and for Selected and Loaded rows the entities are read again by their keys (an entity deleted in the meantime is left out, and the export says how many). If the connection closes or is reconnected while they are read, nothing is saved and a file already at the destination is left as it was. For All matching rows in CSV and Excel the entities are first written to a temporary file next to the export while the columns are collected, so a property that first appears on a later page still gets its columns; the temporary file is removed when the export finishes or stops.
  • Int64 values, GUIDs, DateTimes with all seven fraction digits, Binary values (as base64) and the Doubles NaN, Infinity and -Infinity are written exactly as Azure serves them. Timestamp is written for information; Azure sets it, so it cannot be imported back. Azure does not store the sign of a Double zero, so -0 is exported as 0.
The entity export menu of a table tab with Include type annotations ticked, a note that every property is written with its type, and below it Loaded rows and All matching rows, each with Excel, CSV and JSON.
Include type annotations writes each value’s Azure Table type next to it.

Count entities

Azure Table storage keeps no entity count, so Jam SQL Studio counts on request. On a table's tab, Count on the toolbar reads every page of the table, asking Azure only for each entity's PartitionKey, and shows the total next to the button when it finishes. With a filter on the tab, Count offers Count all entities and Count entities matching the filter; a count made for one filter is shown only while that filter is on the tab. A table's right-click menu in the Object Explorer has Count entities too. The count runs as a job in the Transfers drawer: Cancel stops it and says how many entities were read before it stopped, and Restart counts again from the start. A count is what the reading saw while it ran, not a snapshot of one moment: entities added or deleted during the count may or may not be included. If you change the table in Jam SQL Studio after a count started, the result is marked changed. Counting only reads, so it also works on a read-only connection.

A table tab whose toolbar shows the result of Count, 7 entities, next to Import, above the entity grid.
Count reads every page of the table and shows the number next to the button.

Copy a table

Copy table to… on a table in the Object Explorer, or under More on a table's tab, copies the table's entities into a table on the same or another Azure Storage connection. The copy runs as a job in the Transfers drawer.

  • Target — pick a connected Azure Storage connection with the Table service and a table name (by default the same name on another connection, or NameCopy on the same one). The line under the name says whether the table exists, will be created, or cannot be used (for example, it is the source table itself, also when another connection names the same storage account). Read-only connections are listed but cannot be chosen. Create the table if it does not exist is ticked by default.
  • Existing entities — Skip it leaves an entity the target already has unchanged; Merge sets the source's properties and keeps the others; Replace overwrites the whole entity; Stop the copy stops at the first entity that cannot be written (requests already sent may still complete, and the job names the entity it stopped at).
  • Only entities matching the current filter — offered when the tab has a filter; off by default.
  • Copy MetaInfo declarations — copies the source table's enum and JSON declarations, loose relationships, display column and reference-table flag onto the target table. Declarations the target table already has for the same property are replaced; a relationship it already has is not added twice.

Values keep their types (Int64, Guid, seven-digit DateTime, Binary and the special Doubles); timestamps and ETags are new. Azure writes up to 100 entities of one partition per request, so a table whose entities each have their own PartitionKey is copied one entity per request. In Transfers, the row shows how many entities were copied, skipped, failed or may have been written (the request went out and its answer was lost). Those are never sent again on their own: Retry failed entities… and Retry uncertain entities… start a new job for exactly those entities after saying what that does under the chosen rule, Save error report… saves the list with the reasons, and Open target table opens the copy. A retry you confirmed is not started if the copy ran again in the meantime; check its new result and retry from there. Restart copies from the first entity again. Disconnecting or reconnecting either connection stops the copy; Restart continues it once both are connected.

AI agents can copy a table with the storage_copy_table tool after you approve it. An agent can also ask to create the target table: the approval then names the new table and the storage account it is created on, and nothing is created until you approve. Copying the MetaInfo declarations from an AI request follows Settings → AI Integrations → Allow AI to declare MetaInfo: with Deny the request is refused, with Confirm each the copy's approval also confirms the declarations.

Open containers, queues and tables by name

Some credentials can read a container, queue or table but cannot list the account's: an account SAS without the Service resource type (srt=s) for containers and queues, without the Container resource type (srt=c) for tables, or without the List permission, and a Microsoft Entra identity whose data role is assigned on single containers, queues or tables. Such a connection names what it opens:

  • In the connection form — with Shared access signature or a Microsoft Entra sign-in in Storage account mode, the Open by name row has one box per ticked service (Containers, Queues, Tables). Type the names, separated by commas or new lines. Test connection reads the first name of each service; one readable name is enough to connect.
  • From the Object Explorer — a folder that cannot list shows the reason and an Open container by name… row (or queue / table); the folder's menu and the connection's menu have the same item, and so does the command palette (Azure Storage: Open container by name…). Jam SQL Studio reads the named resource with the connection's own credential before it adds the name; a name that does not exist or that the credential cannot read is refused in the dialog and nothing is saved. On an account that can list, the item only opens the tab.
  • Remove from this connection — on a named container, queue or table, removes the name from the connection. Nothing is sent to Azure.

Named resources are listed without a request to Azure, so the folder shows exactly the names the connection holds. File shares have their own Open share by name… row (see Signing in with Microsoft Entra ID).

Managed disks

An Azure subscription connection works with the managed disks and disk snapshots of a subscription. In the connection form choose Connect using → Azure subscription and enter the subscription ID, or a resource group's resource ID (/subscriptions/…/resourceGroups/…) to reach that resource group only. The connection goes through Azure Resource Manager and signs in with Microsoft Entra ID (Interactive Browser, Service Principal or Azure CLI); account keys and SAS do not apply. Test connection reads the subscription or resource group and reports whether the subscription is registered for Microsoft.Compute. Listing works without the registration; creating snapshots and disks needs it, and a subscription owner registers it in the Azure portal under the subscription's Resource providers.

Object Explorer shows a Managed disks folder with one row per resource group the identity can read. Opening a resource group lists its disks and snapshots in a grid: name, type, size, SKU, state, the VM a disk is attached to, OS type, region, zone and creation time. Copy and export work as in Table Explorer. Properties shows the selected disk's details as Azure reports them, including encryption, network access policy, data access authentication and the unique ID. Open in portal opens the selected disk, or the resource group, in the Azure portal.

ActionWhat it does
Create snapshot…Creates a snapshot of the selected disk or snapshot in the same resource group and region. An incremental snapshot (the default) stores only the changes since the previous one and is always kept on Standard HDD; a full snapshot uses the storage you choose. A name that is already taken is refused. Snapshots are billed for the data they hold.
Upload VHD…Creates a new disk from a fixed VHD file on your computer. Choose VHD… reads the file's footer first: a dynamically expanding or differencing VHD, a VHDX file, or a size Azure cannot use as a disk (it must be a whole number of MiB, at least 20 MiB) is refused there, before anything is created. You choose the name, resource group, region, storage, availability zone, and optionally the OS type, Hyper-V generation, architecture and Microsoft Entra data access. The upload runs in the Transfers drawer and sends only the parts of the file that hold data. Cancel pauses it: the new disk stays in upload state — it cannot be attached and is billed as Standard HDD — until you resume the upload or discard it; Resume continues where it stopped and Discard unfinished… deletes the disk.
Copy…Creates a new disk from the selected disk or snapshot, with the name, resource group, region, storage and availability zone you choose. In another region than the source's, the new disk is created there and filled from the source, which gets read access while the copy runs; Jam SQL Studio revokes the access it granted when the copy ends, and read access granted outside the app stays as it is. A copy to another region that stops starts again from the beginning; a source replaced under its name while the copy waited is refused, and one that started to require Microsoft Entra data access is copied into a disk that requires it too, and a source that denies network access or public network access can only be copied within its region. The copy keeps the source's OS type, Hyper-V generation, architecture, Microsoft Entra data access and network access settings; tags, performance tier and bursting are not copied. Disks encrypted with a customer-managed key, disks reachable only through a private endpoint and Trusted Launch or confidential disks cannot be copied. The copy runs in the Transfers drawer.
Download…Saves the disk or snapshot as a VHD file. Jam SQL Studio grants read access to the disk for up to 24 hours and reads only the parts that hold data. It revokes the access it granted when the download ends; access granted outside Jam SQL Studio is left as it is, and a revoke that fails is shown in the Transfers drawer, where Discard unfinished… tries it again. The download runs in the Transfers drawer: Cancel keeps the partial file. A snapshot's download Resumes where it stopped; a disk's download starts over, because a disk can change while no download holds it. Only one transfer uses a disk at a time: a second download of the same disk is refused until the first ends. A disk attached to a running VM cannot be downloaded (stop and deallocate the VM, or download a snapshot of the disk), and neither can a snapshot that is still being copied or a disk that denies network access.
Delete…Deletes the selected disk or snapshot after you type its name. A disk's snapshots are kept. A disk attached to a VM cannot be deleted, and neither can a disk that a download in Jam SQL Studio is reading. When read access to the disk was granted outside Jam SQL Studio, the confirmation offers Revoke access and delete.

On a read-only connection the Managed disks tab lists disks and shows their properties; snapshot, copy, download and delete are turned off with the reason, because granting access to a disk is a change too. Upload VHD… is turned off too. An Azure subscription connection uses its Azure environment: Resource Manager, sign-in and the portal links of that cloud. Azure Stack Hub environments are refused with the reason, and disks that require Microsoft Entra ID for data access can be downloaded, uploaded or copied to another region in public Azure only. A transfer is never moved to another subscription or resource group: when its connection now points elsewhere, Resume and Restart are refused with the reason, also while the connection is not connected, and you start a new transfer instead.

When Azure does not confirm a change

Sometimes Azure accepts a request but its answer never arrives, or Azure does not let the connection read how the operation ended. Jam SQL Studio records every change it sends to a disk before it sends it, so it knows what may still be running in Azure, also after the app is closed and opened again. Until Azure confirms the outcome, that disk is reserved: a new transfer, delete, snapshot or copy to the same name is refused with the reason, and the transfer's Resume, Restart and Discard unfinished… wait. The transfer row says Outcome unknown. Jam SQL Studio never sends such a change again by itself; only an answer showing that Azure refused the request without acting on it (for example, too many requests) is retried automatically.

  • Pending — the Managed disks toolbar shows Pending (N) while changes are unconfirmed. It opens a list of every unconfirmed change of the connection, also for a disk that no longer appears in the grid (deleted while the app was closed) or a snapshot that never appeared, each with Check and Forget….
  • Check — in the Pending list, on the transfer row, or on the Managed disks toolbar for the selected disk, asks Azure again. When Azure reports how the operation ended, or the result can be seen (a disk or snapshot Jam SQL Studio created exists with the tag naming that request and Azure reports it created, a deleted disk is gone), the reservation ends and the transfer can be resumed, restarted or discarded. When Azure reports that the operation failed, Check says so with Azure's reason and the grid is read again; the change is no longer pending. A failure Jam SQL Studio found on its own stays in the Pending list with Azure's reason until you check it or forget it. A disk that merely looks idle or absent is not taken as an answer, because the operation may still finish, and neither is a disk or snapshot of that name without the tag or one Azure is still creating. Check works on a read-only connection, and refuses a change recorded for another subscription or resource group than the connection now reaches.
  • Forget… — when Azure does not let the connection check the operation, Forget stops tracking it after a warning: if Azure still completes it, a disk may be created or deleted, or read access may stay granted until it expires, without Jam SQL Studio knowing. Forget is refused while Jam SQL Studio is still sending or waiting for that change (a running transfer, its cleanup, or a Delete or snapshot in progress).

A transfer with an unconfirmed change stays in the Transfers drawer: Clear finished and Discard unfinished… leave it there until Check confirms the change or you choose Forget… on the transfer, which lists each change Azure may still complete. Snapshots created from the Managed disks tab carry a transfer-job tag naming the request, and disks created by a copy carry the transfer's.

Frequently asked questions

Can I search blobs by part of a name or by extension?

Yes. Azure filters blob names only by prefix, so Find on the storage browser toolbar scans the listing in the app: type part of a name, a wildcard pattern such as report-202?.json, or an extension such as *.csv, with or without matching case, in the current folder and everything below it or in the whole container. It works for blob containers, Data Lake and file shares, shows how much it scanned, and can be stopped and continued. AI agents use storage_find for the same search. See Find blobs and files by name.

Can I copy or move blobs between containers and storage accounts?

Yes. Select blobs or folders and press Ctrl+C (Cmd+C on macOS), or Ctrl+X to move them, then open the destination container or folder and press Ctrl+V. The destination can be another container, another connection or another storage account, including a Data Lake account. Azure copies the data server-side, so nothing is downloaded. The paste dialog shows what will happen first, and the copy runs as a job in the Transfers drawer with Cancel, Resume and Retry. A move deletes each original only after its copy is checked. Whole containers copy from the tree. See Copy, cut and paste.

Can I view or edit a blob without downloading it?

Yes. Click Preview on the storage browser toolbar and select a file: JSON opens as a tree, formatted text or the raw file, Markdown renders, other text opens in an editor with syntax highlighting, and images, video and audio display in the pane. Edit changes a text file in place; Save replaces it only if it has not changed in Azure since you opened it, and keeps its headers, metadata, index tags and, on Data Lake, its ACL. Save a copy writes your text under another name or in another container. This works for blob containers, Data Lake file systems and file shares. See Preview and edit files.

Can Jam SQL Studio manage ADLS Gen2 ACLs?

Yes. On an account with a hierarchical namespace, Manage access opens an editor for the owner, owning group, access and default ACL entries of one file or directory, with an Effective column that applies the mask. The mask is kept as loaded unless you change it or press Recalculate mask. Propagate access applies a merge, replace or remove to a directory and everything under it as a job in the Transfers panel, with per-path failures, Retry, Resume and Restart. Changing ACLs needs Storage Blob Data Owner or being the owning user of the path. See Access control and Propagate access.

Why can I see my Azure Storage containers but not open them?

Your Microsoft Entra identity holds a management role such as Reader, Contributor or Owner but no data role. Listing containers only needs the management role; reading blobs needs Storage Blob Data Reader (tables and queues have their own Data Reader roles). Test Connection and the error name the missing role. Assign it on the storage account, or, if the identity may read the account keys, switch the connection's Data access to the account key. See which role each operation needs and account-key data access.

Can Jam SQL Studio browse Azure Storage accounts?

Yes. Add an Azure Storage connection and Jam SQL Studio lists the account's blob containers, queues and tables in the Object Explorer. Open a container to browse blobs and virtual folders, upload files or folders, delete with a recoverability-aware confirmation, and download one or more selections through operating-system dialogs. Queue tabs show approximate counts and peek messages without consuming them. A table opens in a grid where you filter, page and edit its typed entities. File shares, SMB and NFS, list under File Shares, where you browse, transfer and manage shares and their snapshots. On an account with a hierarchical namespace (ADLS Gen2) containers open in a Data Lake view with real directories and access control.

Does peeking at an Azure Queue consume its messages?

No. Peek does not change the messages. Receive is separate: it temporarily hides the next messages, and they become visible again when the visibility window elapses unless you delete them first. Updating a received message can change its text and set a new visibility window.

Which Azure Storage authentication methods are supported?

Account Key, Shared Access Signature (account, service or stored-policy SAS), Anonymous for a public container or blob, and Microsoft Entra ID via Interactive Browser sign-in, a Service Principal, or a prior az login through Azure CLI.

Can I run SQL against an Azure Storage connection?

No. Azure Storage has no SQL query language, so SQL editors, notebooks and database compare/import tools are unavailable. Use the storage browser for blobs and Table entities, and Import… on a table to load a CSV, JSON or Excel file into it; AI agents use the storage_* MCP tools.

Does Jam SQL Studio work with the Azurite storage emulator?

Yes. Pick Emulator (Azurite) under Connect using on the connection form for the well-known emulator account and ports, or paste UseDevelopmentStorage=true or the full Azurite connection string. A running Azurite container is also picked up by Detect Local Databases with its published ports.

Which SAS can this connection mint?

An Account Key connection can mint account and service SAS credentials; a Microsoft Entra connection can mint a user-delegation SAS for a blob container, a blob or a Data Lake path. Existing SAS and anonymous connections cannot mint another SAS. Stored-policy mode is available for blob containers, blobs, tables, queues and file shares.

Can I browse NFS file shares?

Yes. Jam SQL Studio reads NFS 4.1 shares on premium FileStorage accounts over the Azure Files REST API, the same way as SMB shares, so nothing is mounted on your machine. You can list, upload, download, create folders, delete, take snapshots and generate a SAS. Uploading over an existing file is not available on NFS shares, so a name collision offers Skip or Keep both, and NFS listings show no modification times.

Why is Archive greyed out?

Archive availability depends on the storage account and Azure region. Jam SQL Studio disables only Archive after Azure reports it unsupported; Hot, Cool and Cold remain available.

Try Jam SQL Studio Today

Download the latest version and browse your Azure Storage accounts alongside your databases.