Azure Managed Redis — replacing Azure Cache for Redis, tiers, clustering policies, Entra authentication from Node.js, Bicep

Using Azure Managed Redis (the Microsoft.Cache/redisEnterprise resource) instead of Azure Cache for Redis, which retires on September 30, 2028 (Enterprise tiers on March 31, 2027) — the four tiers, port 10000 and TLS, OSS vs Enterprise vs non-clustered policies and what each means for clients, Entra authentication (object ID as user, no groups, re-AUTH before expiry, keys disabled), access policy assignments, Bicep where publicNetworkAccess is required, and node-redis with @redis/entraid.

markdownreferencev139J7-4RFFstage: buildtrust: officialservice: redisinterface: iacinterface: sdkAzure Managed RedisAzure Cache for Redis retirement September 30 2028Azure Cache for Redis Enterprise retirement March 31 2027Microsoft.Cache/redisEnterprise@2025-07-01Balanced_B1Memory OptimizedCompute OptimizedFlash Optimizedport 10000clusteringPolicy OSSCluster EnterpriseCluster NoClusterCROSSSLOTRediSearch Enterprise clustering85xx portsnodeAddressMapcreateClusteraccessKeysAuthentication DisabledaccessPolicyAssignmentsaccessPolicyName defaultEntra object ID usernameEntra groups not supported Redishttps://redis.azure.com/.defaultREDIS_SCOPE_DEFAULT@redis/entraidEntraIdCredentialsProviderFactory createForDefaultAzureCredentialexpirationRefreshRatioredisenterprise test-connection --auth entrapublicNetworkAccess requiredprivatelink.redis.azure.nethighAvailability Disabled data lossminimumTlsVersion 1.2

Created 21 Oct 2026 · Modified 23 Oct 2026 · 1 version

Azure Managed Redis

Retirement: move off Azure Cache for Redis

Azure Cache for Redis tierRetiresInstances disabled from
Basic, Standard, PremiumSeptember 30, 2028October 1, 2028
Enterprise, Enterprise FlashMarch 31, 2027April 1, 2027

The replacement is Azure Managed Redis: resource type Microsoft.Cache/redisEnterprise (with a databases/default child), Redis 7.4, host <name>.<region>.redis.azure.net, port 10000, TLS 1.2 or 1.3. New work should target it.

Tiers and clustering

  • Tiers (memory : vCPU): Memory Optimized 8:1, Balanced 4:1, Compute Optimized 2:1, Flash Optimized (cold keys on NVMe; no Search, Bloom or TimeSeries). SKUs look like Balanced_B1, MemoryOptimized_M10, ComputeOptimized_X5.
  • High availability (on by default) keeps replicas across zones where available; turning it off loses data on failure: dev/test only.
clusteringPolicyClientsNotes
OSSCluster (default)Must be cluster-aware: first connection on 10000, then shards on 85xx ports found with CLUSTER NODES (don't hard-code them)Best throughput; multi-key commands need keys in the same hash slot (else CROSSSLOT); no RediSearch
EnterpriseClusterAny client: one endpoint, a proxy routesRequired for RediSearch; only DEL, MSET, MGET, EXISTS, UNLINK, TOUCH may span slots
NoClusterAny clientCaches of 25 GB or less only

The policy can't change once it's OSSCluster or EnterpriseCluster without deleting the database (only NoCluster can change), and not at all with geo-replication.

Entra authentication

  • User name = the object ID of the managed identity or service principal; password = a token for https://redis.azure.com/.default. Entra groups aren't supported; TLS is required; some commands are blocked.
  • Grant access with an access policy assignment (accessPolicyName: 'default', the only one) per principal, or the portal's Authentication blade. Test with the redisenterprise CLI extension (not in core CLI): its test-connection command with --auth entra signs in as your az login identity.
  • Clients must re-send AUTH with a new token at least three minutes before expiry, with jitter: @redis/entraid does this when configured.
  • Then set accessKeysAuthentication: 'Disabled'. Changing it drops every existing connection, Entra ones included; geo-replicated caches must be unlinked first.

Bicep

// Azure Managed Redis (Balanced B1) with access keys off and Entra access for an app identity
param location string = resourceGroup().location
param name string
param appPrincipalId string // object (principal) ID of the app's managed identity

resource cluster 'Microsoft.Cache/redisEnterprise@2025-07-01' = {
  name: name
  location: location
  sku: {
    name: 'Balanced_B1'
  }
  properties: {
    minimumTlsVersion: '1.2'
    publicNetworkAccess: 'Disabled' // required in this API version; reach it through a private endpoint
    highAvailability: 'Enabled' // Disabled is for dev/test only: no replication
  }
}

resource db 'Microsoft.Cache/redisEnterprise/databases@2025-07-01' = {
  parent: cluster
  name: 'default'
  properties: {
    clientProtocol: 'Encrypted'
    port: 10000
    clusteringPolicy: 'OSSCluster' // the default; changing OSS or Enterprise later means deleting the database
    evictionPolicy: 'VolatileLRU'
    accessKeysAuthentication: 'Disabled'
  }
}

resource appAccess 'Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments@2025-07-01' = {
  parent: db
  name: 'app${uniqueString(appPrincipalId)}'
  properties: {
    accessPolicyName: 'default' // the only policy supported
    user: {
      objectId: appPrincipalId
    }
  }
}

output endpoint string = '${cluster.properties.hostName}:10000'

publicNetworkAccess is required on create in API 2025-07-01 (Bicep warns BCP035 without it). Private endpoint: groupId redisEnterprise, zone privatelink.redis.azure.net.

Node.js (node-redis 6 with Entra)

import { isIP } from "node:net";
import { DefaultAzureCredential } from "@azure/identity";
import { EntraIdCredentialsProviderFactory, REDIS_SCOPE_DEFAULT } from "@redis/entraid";
import { createCluster } from "redis";

// REDIS_ENDPOINT looks like "<name>.<region>.redis.azure.net:10000"
const endpoint = process.env.REDIS_ENDPOINT ?? "";
const [host] = endpoint.split(":");

const credentialsProvider = EntraIdCredentialsProviderFactory.createForDefaultAzureCredential({
  credential: new DefaultAzureCredential(),
  scopes: REDIS_SCOPE_DEFAULT, // https://redis.azure.com/.default
  tokenManagerConfig: { expirationRefreshRatio: 0.8 }, // re-authenticate before the token expires
});

// OSSCluster (the default clustering policy) needs a cluster-aware client.
export const redis = createCluster({
  rootNodes: [{ url: `rediss://${endpoint}` }],
  defaults: { credentialsProvider, socket: { tls: true, connectTimeout: 15_000 } },
  // Shards announce IP addresses; map them back to the host name so TLS validation passes.
  nodeAddressMap(address: string) {
    const [h, port] = address.split(":");
    return { host: isIP(h ?? "") !== 0 ? host ?? "" : h ?? "", port: Number(port) };
  },
});

export async function main(): Promise<void> {
  redis.on("error", (e) => console.error("redis", e));
  await redis.connect();
  await redis.set("greeting", "hello", { EX: 60 });
  console.log(await redis.get("greeting"));
  await redis.close();
}

For EnterpriseCluster or NoCluster, use createClient({ url, credentialsProvider, socket }) instead of createCluster. Microsoft's sample maps shard addresses back to the host name with nodeAddressMap; the hub's reading is that without it an OSS-cluster client connects to shard IPs and TLS host-name checks fail.

Read this document as markdown — the same bytes an agent receives.