Environment Variables in Power Platform — Simpler Than You Think
How to create, configure, and use environment variables across Power Apps, Power Automate, and plugins — plus the deployment strategy that keeps things clean.
If you have a flow that points to a SharePoint site URL, and that URL is different in dev, test, and production — you have a configuration problem. Hardcoding the value means you either maintain separate flows per environment or manually edit after every deployment. Both options are bad.
Environment variables solve this. They let you define a configuration key once and set its value per environment. The variable travels with your solution. The value gets set where it’s deployed. This is how configuration should work on Power Platform.
What Environment Variables Are
An environment variable is a Dataverse component that stores a named value. It lives inside a solution, so it moves through your ALM pipeline like any other component — tables, flows, apps.
Each environment variable has two parts:
- Definition — the name, display name, type, and an optional default value
- Current Value — the actual value used at runtime in the current environment
The definition is the schema. The current value is the data. This separation matters for deployment, and I’ll come back to it.
Supported Types
| Type | What it stores | Example use |
|---|---|---|
| Text | A string value | API base URL, site name, email address |
| Number | Decimal number | Retry count, threshold, batch size |
| Yes/No | Boolean (true/false) | Feature flag, debug mode toggle |
| JSON | A JSON object or array | Complex configuration, field mappings |
| Data Source | Reference to a connection (SharePoint site, etc.) | SharePoint site for a canvas app |
| Secret | Reference to an Azure Key Vault secret | API keys, client secrets, tokens |
Text and JSON cover most scenarios. Data Source is specific to canvas apps that need environment-aware connections. Secret is the right choice for anything sensitive — it stores a reference to Azure Key Vault, not the secret itself.
Creating an Environment Variable
You create environment variables inside a solution. Here’s the process:
- Open your solution in make.powerapps.com
- Click New > More > Environment variable
- Fill in the fields:
- Display name — something readable, like
SharePoint Site URL - Name — the schema name, automatically generated (e.g.,
xyz_SharePointSiteURL) - Type — pick from the list above
- Default Value — optional; this is the fallback if no current value is set
- Current Value — the value for this environment
- Display name — something readable, like
- Click Save
The variable now exists in your solution and can be referenced in flows, apps, and code.
Default Value vs Current Value
This distinction trips people up. Here’s the rule:
- Default value is part of the definition. It travels with the solution. It’s the fallback.
- Current value is specific to the environment. It overrides the default.
In practice: set the default value to something safe (your dev environment URL, or leave it blank). After deploying to test or production, set the current value in that environment to the correct value.
If you set the current value in your dev environment and export the solution, that current value does not travel with the managed solution. Only the default value does. This is by design — and it’s a good thing.
Using Environment Variables in Power Automate
This is the most common use case. Anywhere you’d hardcode a URL, a threshold, or a configuration string in a flow, use an environment variable instead.
Step-by-step: reference a variable in a flow
- Open your flow in the solution
- In any action where you need the value, click in the input field
- Open the Dynamic content panel
- Under the solution name, you’ll see your environment variables listed
- Select the one you need — it inserts an expression like
@{parameters('xyz_SharePointSiteURL')}
That’s it. At runtime, Power Automate reads the current value (or the default, if no current value is set) and uses it.
You can also type the expression manually:
@parameters('xyz_SharePointSiteURL')
This works in any text input field in any action.
Where this helps most
- HTTP action URLs — point to different API endpoints per environment
- Send an email actions — different recipient addresses for test vs production
- Condition actions — compare against a configurable threshold
- SharePoint actions — reference the correct site without editing the flow
Using Environment Variables in Canvas Apps
Canvas apps access environment variables through the Environment data source or through a Dataverse lookup. The most reliable method:
- In your canvas app, go to Data > Add data
- Search for and add the Environment Variable Values table and the Environment Variable Definitions table
- Use a
LookUpto read the value:
LookUp(
'Environment Variable Values',
'Environment Variable Definition'.'Schema Name' = "xyz_SharePointSiteURL"
).'Current Value'
If there’s no current value set, fall back to the default:
Coalesce(
LookUp(
'Environment Variable Values',
'Environment Variable Definition'.'Schema Name' = "xyz_SharePointSiteURL"
).'Current Value',
LookUp(
'Environment Variable Definitions',
'Schema Name' = "xyz_SharePointSiteURL"
).'Default Value'
)
Store this in a variable during App.OnStart so you’re not querying Dataverse every time you reference it.
Set(
varSharePointURL,
Coalesce(
LookUp(
'Environment Variable Values',
'Environment Variable Definition'.'Schema Name' = "xyz_SharePointSiteURL"
).'Current Value',
LookUp(
'Environment Variable Definitions',
'Schema Name' = "xyz_SharePointSiteURL"
).'Default Value'
)
);
Then use varSharePointURL wherever you need it in the app.
Using Environment Variables in Plugins (C#)
Plugins don’t have a built-in helper for environment variables. You query Dataverse directly using the environmentvariabledefinition and environmentvariablevalue tables.
Here’s a helper method I use:
public static string GetEnvironmentVariable(IOrganizationService service, string schemaName)
{
// Try to get the current value first
var valueQuery = new QueryExpression("environmentvariablevalue")
{
ColumnSet = new ColumnSet("value"),
Criteria = new FilterExpression()
};
var definitionLink = valueQuery.AddLink(
"environmentvariabledefinition",
"environmentvariabledefinitionid",
"environmentvariabledefinitionid");
definitionLink.LinkCriteria.AddCondition("schemaname", ConditionOperator.Equal, schemaName);
var valueResults = service.RetrieveMultiple(valueQuery);
if (valueResults.Entities.Count > 0)
{
return valueResults.Entities[0].GetAttributeValue<string>("value");
}
// Fall back to default value
var defQuery = new QueryExpression("environmentvariabledefinition")
{
ColumnSet = new ColumnSet("defaultvalue"),
Criteria = new FilterExpression()
};
defQuery.Criteria.AddCondition("schemaname", ConditionOperator.Equal, schemaName);
var defResults = service.RetrieveMultiple(defQuery);
if (defResults.Entities.Count > 0)
{
return defResults.Entities[0].GetAttributeValue<string>("defaultvalue");
}
return null;
}
Call it like this:
var apiUrl = GetEnvironmentVariable(service, "xyz_APIBaseURL");
This method checks for a current value first, then falls back to the default. Keep in mind that this adds a Dataverse query to your plugin execution, so cache the result if you’re calling it repeatedly in the same execution context.
Deployment Strategy
This is where environment variables pay for themselves — or cause headaches if you set them up wrong.
The two-solution approach
The pattern that works best:
Solution 1 (Core): Contains the environment variable definitions with sensible default values. This solution is deployed to every environment.
Solution 2 (Config per environment): Contains only the current values. You create one config solution per target environment. Each config solution sets the values appropriate for that environment.
This way:
- Your main solution is identical everywhere
- Configuration is explicit, version-controlled, and deployable
- Nobody has to manually set values after import
Alternative: set values after deployment
If the two-solution approach feels like too much overhead for a small project, you can set the current values manually in each environment after deploying the main solution:
- Go to the solution in the target environment
- Open the environment variable
- Set the current value
- Save
This works fine for small teams. It breaks down when you have multiple environments, frequent deployments, or team members who forget the step.
Common Mistakes
Hardcoding values instead of using environment variables
The most common one. Someone puts a SharePoint URL directly in a flow action, the flow gets deployed to production, and it’s still pointing at the dev SharePoint site. Environment variables exist to prevent this. Use them for any value that differs between environments.
Forgetting to set current values after deployment
You deploy your solution to production. The environment variable definition arrives with its default value, but nobody sets the current value. If the default points to a dev resource, production is now talking to dev. Always verify environment variable values as part of your deployment checklist.
Setting the current value in dev before export
If you set a current value in your dev environment and export an unmanaged solution, the current value comes along. When you import it as managed, that dev-specific value is now the current value in the target environment. Either clear the current value before export or use the two-solution approach described above.
Using environment variables for secrets without Key Vault
Text-type environment variables store values in plain text in Dataverse. Anyone with read access to the environmentvariablevalue table can see them. For API keys, passwords, and tokens, use the Secret type with Azure Key Vault. It requires more setup but keeps sensitive data where it belongs.
Quick Reference
| Task | Where |
|---|---|
| Create a variable | Solution > New > More > Environment variable |
| Set current value | Open the variable in the target environment’s solution |
| Use in Power Automate | Dynamic content panel > select the variable, or @parameters('schema_name') |
| Use in canvas app | Query Environment Variable Values and Environment Variable Definitions tables |
| Use in a plugin | Query environmentvariablevalue / environmentvariabledefinition via IOrganizationService |
| Deploy values separately | Two-solution approach: definitions in one, current values in another |
Environment variables are one of those features that take five minutes to set up and save hours of debugging configuration mismatches across environments. If you’re still hardcoding URLs and toggling flags by editing flows after deployment, this is the fix.
Related articles
Power Platform Licensing: What I Wish Someone Told Me on Day One
Licensing isn't a procurement problem — it's an architecture decision. Here's the mental model every solution architect needs before starting a Power Platform project, with real scenarios and a pre-project checklist.
Power Platform Questions I See Every Week (And Their Real Answers)
A collection of the most common Power Platform developer questions — from delegation errors to Dataverse throttling — with answers that go beyond the official docs.
Low Code Isn't a Shortcut. It's a Different Trade-Off.
The debate around low-code platforms usually generates more heat than light. Here's a grounded take on when Power Platform is genuinely the right tool — and when it isn't.