agentsclimarketplace

Optimizing azure blob storage cost

Skill alexpizarro/azure-lean-stack-skills/skills/optimizing-azure-blob-storage-cost

Azure apps that cost nothing when nobody's using them. A Claude Code skill pack — 14 composable skills, 37+ documented gotchas, branch-per-env CI/CD.

Install
npx -y skills add alexpizarro/azure-lean-stack-skills --skill optimizing-azure-blob-storage-cost

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Configures Azure Blob Storage with lifecycle rules that auto-delete stale temp blobs and tier production data through Hot → Cool → Cold without rehydration latency. Provides CORS rules tuned for SPA + SAS uploads/Range reads, public-read branding container alongside private app containers, and SKU/redundancy guidance to keep cost minimal. Use when adding blob storage for uploads, designing storage for a media-heavy app, or auditing an existing storage account for cost waste.

SKILL.md

6.4 KB, as published. Nobody here has run it

Optimizing Azure Blob Storage Cost

Default-low-cost blob storage with lifecycle rules tuned for media workloads (and any pattern with ephemeral temp blobs + long-lived primary blobs).

When to invoke

  • Adding a blob storage account to a project
  • Designing for uploads (SAS-based) + serving (Range / CORS)
  • Auditing an existing storage account that's growing unbounded
  • A project that stores media (video, large images, archives) where retention > 60 days

The two-pattern playbook

Pattern A: temp + permanent containers

Most apps have two flavours of blob:

  • Temp — short-lived working data (uploads being processed, intermediate transformations, cache)
  • Permanent — user-visible content (videos, images, exports)

Apply different lifecycle rules to each:

resource tempBlobLifecycle 'Microsoft.Storage/storageAccounts/managementPolicies@2023-05-01' = {
  parent: storageAccount
  name: 'default'
  properties: {
    policy: {
      rules: [
        // Rule 1: delete stale temp blobs after 7 days
        {
          enabled: true
          name: 'delete-stale-temp-blobs'
          type: 'Lifecycle'
          definition: {
            filters: {
              blobTypes: ['blockBlob']
              prefixMatch: ['incoming/', 'processor-jobs/', 'tmp/']
            }
            actions: {
              baseBlob: { delete: { daysAfterModificationGreaterThan: 7 } }
            }
          }
        }
        // Rule 2: age permanent blobs through tiers — NEVER use Archive for
        // playable/viewable content (rehydration takes hours)
        {
          enabled: true
          name: 'tier-aging-content'
          type: 'Lifecycle'
          definition: {
            filters: {
              blobTypes: ['blockBlob']
              prefixMatch: ['videos/', 'images/', 'exports/']
            }
            actions: {
              baseBlob: {
                tierToCool: { daysAfterModificationGreaterThan: 60 }
                tierToCold: { daysAfterModificationGreaterThan: 180 }
                // intentionally NO tierToArchive — needs rehydration
              }
            }
          }
        }
      ]
    }
  }
}

See references/lifecycle-rules.md.

Pattern B: per-container public/private

Most containers stay private (publicAccess: 'None') with SAS-based access. One opt-in public-read container for assets that need to be served via plain URLs (branding, public catalog images):

resource brandingContainer 'Microsoft.Storage/storageAccounts/blobServices/containers@2023-05-01' = {
  parent: blobService
  name: 'branding'
  properties: { publicAccess: 'Blob' }    // read-only public access
}

To allow this, the storage account itself must set allowBlobPublicAccess: true. Other containers remain publicAccess: 'None' — that's the explicit per-container setting.

Storage account defaults

resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
  kind: 'StorageV2'
  sku: { name: 'Standard_LRS' }            // LRS = cheapest. Use GRS only when DR matters.
  properties: {
    accessTier: 'Hot'                      // Hot for new blobs (lifecycle ages them later)
    supportsHttpsTrafficOnly: true
    minimumTlsVersion: 'TLS1_2'
    allowBlobPublicAccess: true            // gated per-container; flip to false if no public container exists
  }
}
SettingDefaultWhen to change
sku.nameStandard_LRSStandard_GRS for geo-redundant backups (~2× cost)
accessTierHotSet Cool at account level if 95%+ of writes are write-once-read-rarely
allowBlobPublicAccesstrue only if a public container existsfalse otherwise — defence in depth

See references/access-tiers.md.

CORS for SPA + SAS

Browser uploads via SAS and Range reads (e.g. video players with crossOrigin="anonymous") need CORS:

resource blobService 'Microsoft.Storage/storageAccounts/blobServices@2023-05-01' = {
  parent: storageAccount
  name: 'default'
  properties: {
    cors: {
      corsRules: [
        {
          allowedOrigins: [
            'https://app.example.com'
            'http://localhost:5173'
          ]
          allowedMethods: ['GET', 'PUT', 'OPTIONS']
          allowedHeaders: ['*']
          exposedHeaders: ['*']                    // required for Range responses
          maxAgeInSeconds: 3600
        }
      ]
    }
  }
}

See references/cors-for-spa.md.

The Archive trap

Do not use tierToArchive in lifecycle rules for content that needs to stay playable. Archive tier requires manual rehydration that takes 1–15 hours and bills extra. Symptoms:

  • Video plays fine for 90 days, then suddenly returns 409 Conflict
  • Image URLs return RehydrationRequired errors
  • Customer support tickets that take hours to resolve

Use Cold instead (~$0.0036/GB/month). Cold is still online and instantly accessible.

Storage naming

Storage account names must be lowercase, alphanumeric, ≤24 chars:

{org}{project}store{env}     e.g. acmetaskappstoretest

If the resulting name exceeds 24 chars, shorten project or drop the store suffix.

Composes with

Templates

FilePurpose
templates/storageAccount-with-lifecycle.bicepStorageV2 + lifecycle + CORS + private/public containers

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.