Skip to content
Get Started for Free

Table Storage

Azure Table Storage is a NoSQL key-value store designed for large volumes of semi-structured data, useful for lightweight metadata, lookup records, and simple operational datasets. Data is organized into tables, partitions, and entities addressed by PartitionKey and RowKey. It offers schemaless flexibility at a fraction of the cost of traditional SQL, making it easy to adapt as your application evolves. For more information, see What is Azure Table storage?

LocalStack for Azure provides a local environment for building and testing applications that make use of Azure Table Storage. The supported APIs are available on our API Coverage section, which provides information on the extent of Table Storage’s integration with LocalStack.

This guide is designed for users new to Table Storage and assumes basic knowledge of the Azure CLI and our lstk az proxy.

Launch LocalStack using your preferred method. For more information, see Introduction to LocalStack for Azure. Once the container is running, enable Azure CLI interception by running:

Terminal window
lstk az start-interception

This command points the az CLI away from the public Azure management REST API and toward the LocalStack for Azure emulator API. To revert this configuration, run:

Terminal window
lstk az stop-interception

This reconfigures the az CLI to send commands to the official Azure management REST API.

Create a resource group to contain your storage resources:

Terminal window
az group create \
--name rg-table-demo \
--location westeurope
Output
{
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-table-demo",
"location": "westeurope",
"managedBy": null,
"name": "rg-table-demo",
"properties": {
"provisioningState": "Succeeded"
},
"tags": null,
"type": "Microsoft.Resources/resourceGroups"
}

Create a storage account in the resource group:

Terminal window
az storage account create \
--name sttabledemols \
--resource-group rg-table-demo \
--location westeurope \
--sku Standard_LRS
Output
{
...
"id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-table-demo/providers/Microsoft.Storage/storageAccounts/sttabledemols",
...
"name": "sttabledemols",
...
"placement": null,
"primaryEndpoints": {
"blob": "https://sttabledemols.blob.core.azure.localhost.localstack.cloud:4566",
...
"table": "https://sttabledemols.table.core.azure.localhost.localstack.cloud:4566",
...
},
....
}

There are three ways to authenticate storage table commands against the emulator:

Retrieve the account key and pass it with --account-name and --account-key:

Terminal window
ACCOUNT_KEY=$(az storage account keys list \
--account-name sttabledemols \
--resource-group rg-table-demo \
--query "[0].value" \
--output tsv)
az storage table list \
--account-name sttabledemols \
--account-key "$ACCOUNT_KEY"

Use --auth-mode login to authenticate with the current session credentials:

Terminal window
az storage table list \
--account-name sttabledemols \
--auth-mode login

Bundle the account name and key into a single value:

Terminal window
CONNECTION_STRING=$(az storage account show-connection-string \
--name sttabledemols \
--resource-group rg-table-demo \
--query connectionString -o tsv)
az storage table list \
--connection-string "$CONNECTION_STRING"

The remaining examples in this guide use connection strings for brevity.

Create a table:

Terminal window
az storage table create \
--name apptable \
--connection-string "$CONNECTION_STRING"
Output
{
"created": true
}

Verify the table exists:

Terminal window
az storage table exists \
--name apptable \
--connection-string "$CONNECTION_STRING"
Output
{
"exists": true
}

List tables in the storage account:

Terminal window
az storage table list \
--connection-string "$CONNECTION_STRING"
Output
[
{
"name": "apptable"
}
]

Insert an entity into the table:

Terminal window
az storage entity insert \
--table-name apptable \
--entity PartitionKey=demo RowKey=1 name=Alice score=100 \
--connection-string "$CONNECTION_STRING"
Output
{
"content": {
"PartitionKey": "demo",
"RowKey": "1",
"name": "Alice",
"score": 100,
...
},
"etag": "W/\"datetime'...'\"",
...
}

Retrieve the entity by its partition key and row key:

Terminal window
az storage entity show \
--table-name apptable \
--partition-key demo \
--row-key 1 \
--connection-string "$CONNECTION_STRING"
Output
{
"PartitionKey": "demo",
"RowKey": "1",
"name": "Alice",
"score": 100,
...
}

Query entities by partition key:

Terminal window
az storage entity query \
--table-name apptable \
--filter "PartitionKey eq 'demo'" \
--connection-string "$CONNECTION_STRING"
Output
{
"items": [
{
"PartitionKey": "demo",
"RowKey": "1",
"name": "Alice",
"score": 100,
...
}
],
"nextMarker": {}
}

Update the entity with a merge operation:

Terminal window
az storage entity merge \
--table-name apptable \
--entity PartitionKey=demo RowKey=1 score=101 \
--connection-string "$CONNECTION_STRING"
Output
{
"etag": "W/\"datetime'...'\"",
...
}

Delete the entity and verify the table is empty:

Terminal window
az storage entity delete \
--table-name apptable \
--partition-key demo \
--row-key 1 \
--connection-string "$CONNECTION_STRING"
az storage entity query \
--table-name apptable \
--connection-string "$CONNECTION_STRING"
Output
{
"deleted": null
}
{
"items": [],
"nextMarker": {}
}

The Table Storage emulator supports the following features:

  • Data plane REST API: Table CRUD, entity operations (insert, query, merge, replace, delete), OData query filters, and batch/transaction requests.
  • Control plane REST API: Create, get, update, and delete tables, and get and set table service properties via Azure Resource Manager.
  • Table update: Updating a table creates it if it doesn’t exist (upsert) and stores its access policies. A table accepts up to 5 access policies, and passing [] clears them.
  • Table service properties: Setting service properties stores what you send (such as CORS rules), validated as Azure does, and getting them returns the stored values. Setting an empty value echoes an empty resource.
  • Persistence: With persistence enabled, table data survives a restart.
  • Multiple authentication modes: Storage account key, login credentials, and connection strings.
  • SAS and Shared Key validation: Shared Key, SharedKeyLite, and account, service, and user delegation SAS requests are validated. A service SAS must name the table it signs (tn). See Storage Account: Data plane authentication.
  • Entity operations: Insert, query, show, merge, replace, and delete entities with schemaless, key-value data addressed by PartitionKey and RowKey.
  • OData query support: Filter and project entities using OData expressions (e.g., PartitionKey eq 'demo').
  • Batch operations: Entity batch (transaction) requests are proxied with correct URL and authorization rewriting.
  • Persistence must be enabled: Table data survives a restart only when persistence is on. Without it, table data is lost when the LocalStack emulator is stopped or restarted.
  • Service properties are stored, not applied: The emulator stores and returns the settings you set, such as CORS rules, but doesn’t act on them.
  • Unsupported control plane operations: Table list and table service list are not yet supported.
  • Storage account keys: Keys are emulator-generated rather than managed by Azure.
  • Header validation: Unsupported request headers or parameters are silently accepted (Azurite runs in loose mode) instead of being rejected.
  • API version enforcement: The emulator does not validate the x-ms-version header; all API versions are accepted.
  • RBAC enforcement is opt-in: By default, data-plane operations succeed regardless of role assignments. Set LS_AZURE_ENFORCE_RBAC to require the caller to hold a role such as Storage Table Data Contributor; see Role Assignment: Enabling RBAC enforcement.

The following sample demonstrates how to use Table Storage with LocalStack for Azure:

8 of 8 operations implemented

Operation ▲Implemented ▼
Page 1 of 0
Was this page helpful?