Using inline() function for runtime parameter overrides in Azure Bicep

Learn how to use the new inline() function in Azure Bicep to provide runtime parameter overrides directly within your deployments.

Using inline() function for runtime parameter overrides in Azure Bicep

You've been there. You create a .bicepparam file, leave out a required parameter because you want to supply it at deployment time, and Bicep throws a BCP258 error in your face.

Bad luck? Maybe.

That error makes perfect sense from a validation perspective. But it broke a legitimate workflow: providing sensitive values like passwords, API keys, or environment-specific configurations at the command line during deployment.

The inline() (or the syntactic sugar externalInput() function) function fixes this. It's a placeholder that tells Bicep, "I'll provide this value later." No errors and no workarounds needed. Just clean parameter files that defer values to deployment time.

This blog post dives into the problem it solves, how it works, and provides real-world examples.

The problem this solves

Before inline(), you had a few options, but none were splendid for every scenario:

  1. Use the getSecret() function to reference Azure Key Vault secrets (great for secrets already in Key Vault).
  2. Use readEnvironmentVariable() to read environment variables at compile time (works, but requires setting the variable before compilation).
  3. Hardcode values in your .bicepparam file (don't do this).
  4. Remove required parameters and deal with validation errors (bad for peace of mind).

The inline() function fills a specific gap. While Key Vault functions work when secrets are stored in Azure, and readEnvironmentVariable() works for compile-time environment variables, inline() shines when you need to:

  • Deploy the sample template to multiple environments with different credentials.
  • Provide secrets through Azure CLI (or Azure PowerShell soon)
  • Use DevOps pipelines that inject parameters at runtime.

How inline() works

The inline() function acts as a placeholder in your parameter file. When you build your parameters with overrides, Bicep replaces `inline()` with the actual value you provide.

Here's the syntax:

using './main.bicep'

param apiKey = inline()
param connectionString = inline()
param environment = 'production'

At build time, you provide the override values:

az bicep build-params main.bicepparam \
  --parameters-override apiKey="secret-key-123" \
  --parameters-override connectionString="Server=..."

The generated parameters file includes your runtime values without ever exposing them in source control.

Real-world examples

Theory is nice. But let's see how inline() solves actual problems you might face every day.

Example 1: Multi-environment deployments

You're deploying to dev, staging, and production. Each environment needs different database credentials:

using './database.bicep'

param serverName = 'sql-${environment}'
param adminUsername = inline()
param adminPassword = inline()
param environment = inline()

The deployment commands:

# Dev environment
az bicep build-params params.bicepparam \
  --parameters-override environment="dev" \
  --parameters-override adminUsername="dev-admin" \
  --parameters-override adminPassword="${DEV_PASSWORD}"

# Staging environment
az bicep build-params params.bicepparam \
  --parameters-override environment="dev" \
  --parameters-override adminUsername="dev-admin" \
  --parameters-override adminPassword="${STAGING_PASSWORD}"

# Production environment
az bicep build-params params.bicepparam \
  --parameters-override environment="prod" \
  --parameters-override adminUsername="prod-admin" \
  --parameters-override adminPassword="${PROD_PASSWORD}"

Example 2: Nested object properties

The inline() function works inside object properties, not just top-level parameters:

using './app.bicep'

param config = {
  appName: 'my-app'
  secrets: {
    apiKey: inline()
    clientSecret: inline()
  }
  region: 'eastus'
}

When you override, use the property name as the key:

az bicep build-params app.bicepparam \
  --parameters-override apiKey="key-value" \
  --parameters-override clientSecret="secret-value"

Example 3: DevOps pipeline integration

In GitHub Actions or Azure Pipelines, you can inject secrets without storing them in parameter files:

- name: Build Bicep Parameters
  run: |
    az bicep build-params production.bicepparam \
      --parameters-override sqlPassword="${{ secrets.SQL_PASSWORD }}" \
      --parameters-override apiKey="${{ secrets.API_KEY }}" \
      --stdout > parameters.json

Important constraints

The inline() function has specific rules about where it can appear in your parameter files. These constraints exist to maintain type safety and ensure predictable behavior during the build process.

You CAN use inline():

  • In parameter assignments
  • In object property values
  • In array elements

You CANNOT use inline():

  • In variable declarations
  • In string interpolation
  • In decorators

If you try using inline() in an invalid location, you'll get a clear error message telling you why.

Choosing your approach: inline() vs alternatives

Here's the thing: Bicep gives you multiple tools for the same job, and that's actually a good thing. Each approach has its moment to shine. I've used all three, and here's what I've learned about when each one makes the most sense.

Use inline() for values provided via CLI at build time:

param apiKey = inline()  // Provided via --parameters-override

Use readEnvironmentVariable() for compile-time environment variables:

param apiKey = readEnvironmentVariable('API_KEY')
param apiKeyWithDefault = readEnvironmentVariable('API_KEY', 'default-value')

Use kv.getSecret() for secrets already in Key Vault:

resource kv 'Microsoft.KeyVault/vaults@2025-05-01' existing = {
  name: 'my-keyvault'
}

module app 'app.bicep' = {
  name: 'app'
  params: {
    apiKey: kv.getSecret('apiKey')  // Retrieved from Key Vault at deployment
  }
}

The key differences:

  • inline(): Value provided explicitly via CLI flag at build time.
  • readEnvironmentVariable(): Value read from environment variable during compilation.
  • getSecret(): Value retrieved from Azure Key Vault during deployment.

And honestly? Skip inline() if the value is known at authoring time—just hardcode it. The same goes for non-sensitive, environment-agnostic parameters. If your secret is already sitting in Key Vault, use getSecret() instead. And if you've already got environment variables set up on your build machine, readEnvironmentVariable() provides cleaner syntax with less ceremony.

Summary

The inline() function is available in the nightly builds of Bicep and is likely to be released in Bicep v0.39+. To use it, start updating your .bicepparam files and use the az bicep build-params with --parameters-override flags.

That's it. No additional configuration required. Just a cleaner way to handle runtime parameter values.

The next time you need to provide a password during deployment, you'll know exactly what to do.