Create and use environment variables
The previous unit leaves off with a forecast: Contoso needs a way to keep values like the external device-availability service endpoint portable as the equipment-provisioning solution moves between environments. This unit picks that up directly, shifting your focus from what can safely change in a solution to what you should never hardcode into it in the first place.
You move from embedding environment-specific values directly in components to externalizing them into configuration that travels cleanly with the solution.
Treat environment-specific values as configuration, not code
Contoso's solution has at least three values that look different in dev, test, and production. The endpoint URL for the external service reports device availability. The approval threshold defines the maximum device value an IT coordinator can auto-approve without escalation. And the API key is what the flow uses to authenticate against that external service.
If you type any of these values directly into a flow action or a plug-in, the solution itself is no longer identical across environments. That's exactly the condition that application lifecycle management (ALM) depends on avoiding.
Environment variables solve this by storing a parameter key and value as their own solution component, separate from the canvas app, flow, or plug-in that consumes it. The component references the key; the value comes from the environment variable.
This separation means one environment variable can feed many components at once. If Contoso's device-availability endpoint changes, a single environment variable update flows through to every flow and app that reads it. There's no need to search through actions or hardcoded strings component by component.
That separation also exists one level deeper, inside the environment variable itself. A definition describes the variable: its name, data type, and an optional default value. A value is a separate record that holds the current value actually used in a given environment.
A current value always takes precedence over a default value when both exist, but a value can't exist without a definition. The definition is what travels with the solution, and the current value is what makes it match a specific environment.
Match the data type to the kind of value you're protecting
Creating an environment variable means choosing a data type, and that choice is a decision about how the value behaves, not just how it's formatted. The following table maps Contoso's three variable candidates to the data types that fit them:
| Contoso value | Data type | Why this type fits |
|---|---|---|
| Device-availability service endpoint URL | Text | A simple string that differs by environment but carries no special handling |
| Approval auto-escalation threshold | Decimal number | A numeric comparison value a flow or business rule evaluates directly |
| API key for the device-availability service | Secret | Credentials that must never appear in plain text inside a flow or solution export |
Text, Decimal number, JSON, and Two options cover most configuration values and work the same way: you set a current value and optionally a default value, and components read whichever one applies.
Data source is a different case. It applies when a canvas app or flow connects to an external data source like SharePoint or SQL Server. The connection needs more than just credentials to resolve, such as which site or table to use. The connection itself isn't stored in the environment variable; only the extra information needed to reconnect is.
Secret is the type that matters most for Contoso's API key. Rather than storing the key value in Dataverse, a Secret-type environment variable references a secret held in Azure Key Vault. Power Platform retrieves it at run time, once the key vault is configured to allow that access. The key material never passes through the solution, the flow designer, or a solution export file. Only the reference to where it lives does.
Secret-type values can be used only by Power Automate flows, Copilot Studio agents, and custom connectors, not by plug-ins or general API calls. For a Secret-type variable to resolve, the key vault must be in the same tenant, its subscription must have the Microsoft.PowerPlatform resource provider registered, and the Dataverse service principal needs the Key Vault Secrets User role.
Guiding question: For Contoso's approval threshold, would you expose it as a value every environment is expected to override? Or would you let it ship with a sensible default that only test or production occasionally changes? What does your answer depend on: who owns the value, and how often does it change?
Carry the value, not just the reference, across environments
Moving Contoso's solution from dev to test to production is where the definition-and-value separation earns its purpose. The environment variable definition is a managed solution component, so it travels with every export and import like any other piece of the solution. The current value, by contrast, counts as data tied to the environment it lives in.
| Characteristic | Default value | Current value |
|---|---|---|
| Where it lives | Part of the environment variable definition | Its own value record, separate from the definition |
| When it's used | Only when no current value exists | Takes precedence over the default whenever present |
| Behavior on export | Travels with the definition | Removable before export |
| Typical use | A sensible value every environment can start from | An environment-specific override, like a production endpoint |
Before exporting Contoso's solution from the development environment, you can remove the current value from an environment variable. This keeps the definition in the solution, while letting the next environment supply its own current value during import. If a default value or an existing target value already exists, Power Platform can use that value instead of prompting.
This is exactly how the device-availability endpoint and the API key reference should move: the definition ships in the solution, and each environment supplies its own current value as needed.
This same behavior is what makes environment variables usable in automated pipelines. SolutionPackager can unpack a solution into source control, with environment variable values broken out into their own files. This lets Contoso's team keep a separate values file per target environment, and have the packaging tooling apply the right one depending on where the pipeline deploys.
Learn more about environment variables and using Azure Key Vault secrets with environment variables.
Avoid the shortcuts that undo the benefit
A few habits determine whether environment variables actually deliver the portability they promise, or add an extra layer of indirection around values that still get hardcoded somewhere. Typing a connection string or endpoint into a flow action "just this once" because a deadline is close erases the exact guarantee environment variables exist to provide. The next environment inherits that hardcoded value whether it's correct there or not.
Deciding between a default value and a current value deserves the same deliberateness as choosing a data type. A default value that's meant to be overridden in every environment creates a false sense of safety: nobody notices it's wrong until production behaves like development. Treat default values as genuine fallbacks, not placeholders for values every environment must supply.
Secrets deserve a type of their own for a reason. Storing Contoso's API key as Text instead of Secret puts credential material directly in Dataverse and in every solution export, which is the opposite of what a secure deployment needs. Reserving Secret-type variables, and the Key Vault configuration behind them, for anything resembling a credential keeps that material out of source control, export files, and the flow designer entirely.
With environment variables carrying Contoso's configuration cleanly across environments, the next unit turns to how Microsoft Power Platform pipelines orchestrate that movement with approval gates and custom deployment steps.