Azure / Azure/azure-dev

Add `azd env export` for app-friendly config formats and local development workflows

Open
#7,434 0 comments 0 reactions 0 assignees View on GitHub
area/core-cli feature needs-discussion
Dominant language
Go
Stars
569
Forks
364
Avg merge
2d 19h
Merged PRs (30d)
136

Description

## Summary

Issue #4384 highlights a second, separate need beyond "run a command with azd env loaded": users also need a standard way to export selected azd environment values into app-facing configuration files.

The primary scenario here is:

> I want to develop my app locally using azd's provisioned outputs

This issue proposes a first-class `azd env export` command focused on writing azd environment values into app-friendly configuration formats such as:

- `.env`
- generic JSON
- other known language/framework configuration files over time

This command should support:

- exporting only a subset of keys
- excluding keys ergonomically when starting from a broader selection
- merge/update behavior for existing files
- app-friendly output formats instead of raw shell export syntax

This is intentionally separate from `azd env exec`:

- `env exec` solves "run a process with azd env loaded"
- `env export` solves "write selected azd values into a config file my app expects"

Related issue: https://github.com/Azure/azure-dev/issues/7423

This is also intentionally separate from a future auto-export / auto-sync feature:

- `env export` is the manual command for exporting azd values into app-facing config files
- auto-export / auto-sync is a follow-up feature for keeping those files updated automatically

Related issue: https://github.com/Azure/azure-dev/issues/7544

## What

We should add a command that can export values from the selected azd environment into common local development configuration formats.

Working shape:

```bash
azd env export [flags]
```

Examples:

```bash
# infer format from destination filename
azd env export --out .env.local

# export a subset of keys
azd env export --out web/.env --include AZURE_CLIENT_ID --include AZURE_TENANT_ID

# export most keys, but exclude a few azd-specific ones
azd env export --out web/.env --exclude AZURE_ENV_NAME --exclude AZURE_SUBSCRIPTION_ID

# filter keys and merge into an existing file
azd env export --out web/.env --filter '^VITE_|^AZURE_CLIENT_ID$'

# export generic JSON for tools that already know how to consume JSON
azd env export --out azd-env.json \
--include AZURE_OPENAI_ENDPOINT=AzureOpenAI:Endpoint

# export from a specific azd environment
azd env export -e myenv --out api/.env

# rename a key during export
azd env export --out .env.local \
--include AZURE_CLIENT_ID=VITE_AZURE_CLIENT_ID

# preview changes without writing
azd env export --out web/.env --dry-run

# override inferred format when needed
azd env export --out local.settings.json --format dotenv

# .NET: export JSON and pipe to user-secrets
azd env export --format json \
--include AZURE_OPENAI_ENDPOINT=AzureOpenAI:Endpoint \
--include AZURE_OPENAI_KEY=AzureOpenAI:Key \
| dotnet user-secrets set
```

At a high level, this should let users say:

> take selected values from the current azd environment and write them into the config file my app actually uses

without having to hand-roll scripts around `azd env get-value`, manually copy/paste values, or write one-off sync tools per template.

## Why

Today, users often need app configuration files that are narrower than the full azd environment.

That shows up in a few recurring scenarios from #4384:

1. A project already uses a framework-specific `.env` file and only wants a few azd-managed values added or refreshed
2. A user wants local-development-first workflows where the app config file exists before `azd provision`, and later `azd` should update only the relevant keys
3. A sample wants to export values for a specific framework format rather than asking users to inspect the raw azd environment
4. Teams want a supported alternative to custom scripts that repeatedly call `azd env get-value`

The current workarounds are awkward:

- `azd env get-values > .env` dumps too much and includes azd-oriented values that may not belong in the app file
- calling `azd env get-value` repeatedly is tedious and brittle
- custom scripts vary across templates and languages
- merge/update behavior is left to each template author to reinvent

This directly addresses the underlying issue in #4384 by making "export selected values for app consumption" a first-class azd workflow rather than an emergent pattern built from lower-level commands.

Together with `env exec` in https://github.com/Azure/azure-dev/issues/7423, this gives us a cleaner split between:

- "run my app/script with azd env loaded"
- "write selected azd values into the app config my project uses"

## Current state

`azd` already exposes the raw ingredients:

- `azd env get-values` returns the full environment
- `azd env get-value ` can fetch specific keys
- `azd env list --output json` exposes `DotEnvPath`

But the missing first-class behavior is:

> export a subset of azd values into an app config file, in the format that app or tool expects, with safe update semantics

That gap is why templates keep reaching for ad hoc scripts and manual instructions.

## Proposed high-level changes

### 1. Add a dedicated `env export` command

Introduce a command oriented around file export/update workflows rather than raw environment inspection.

For example:

```bash
azd env export --out .env.local
azd env export --out azd-env.json
azd env export --out local.settings.json --format dotenv
```

This should be a separate command from `env get-values` so the intent is clear:

- `get-values` is for raw inspection and scripting primitives
- `export` is for file-oriented app configuration workflows

### 2. Support known output formats

Initial format support should include:

- `.env` / dotenv output
- generic JSON output

The design should also allow additional known formats over time, but v1 does not need azd to deeply understand every framework-specific file format.

Filename-based format inference should be a key part of the experience.

In the common case, users should only need to specify the destination file:

```bash
azd env export --out .env.local
azd env export --out azd-env.json
```

`azd` should infer the output format from the filename when possible, while still allowing `--format` to override or make the choice explicit when needed:

```bash
azd env export --out local.settings.json --format dotenv
```

Potential format names:

- `dotenv`
- `json`
- future framework-specific formats as needed

This gives us room to support app-friendly conventions without forcing azd to immediately own deep knowledge of every language-specific config file shape.

### 3. Support subset selection ergonomically

The command should make it easy to export only the keys the app needs, while also allowing optional renaming or path mapping without introducing a second concept.

That likely means supporting one or more of:

- repeated `--include `
- repeated `--include =`
- repeated `--exclude `
- `--filter ` for regex or glob matching

The cleanest model is to let `--include` handle both selection and optional mapping:

- `--include AZURE_CLIENT_ID`
- `--include AZURE_OPENAI_ENDPOINT=AzureOpenAI:Endpoint`
- `--include AZURE_CLIENT_ID=VITE_AZURE_CLIENT_ID`

That keeps a single mental model:

> these are the azd keys I want exported, optionally with a different destination name/path

Filtering can still exist as a convenience for broader patterns, but repeated `--include` is the most explicit and script-friendly form.

`--exclude` is also useful and ergonomic when users want to start from a broader selection model and remove a few known-problematic keys such as `AZURE_ENV_NAME`.

Examples:

```bash
azd env export --format dotenv --out web/.env \
--include AZURE_CLIENT_ID \
--include AZURE_TENANT_ID

azd env export --out appsettings.Development.json \
--include AZURE_OPENAI_ENDPOINT=AzureOpenAI:Endpoint \
--include AZURE_OPENAI_KEY=AzureOpenAI:Key

azd env export --format dotenv --out .env.local \
--include AZURE_CLIENT_ID=VITE_AZURE_CLIENT_ID

azd env export --format dotenv --out web/.env \
--filter '^(VITE_|AZURE_CLIENT_ID$)'

azd env export --out web/.env \
--exclude AZURE_ENV_NAME \
--exclude AZURE_SUBSCRIPTION_ID
```

This borrows from familiar `source=target` config patterns while keeping everything under one flag instead of splitting selection and mapping into separate concepts.

### 4. Merge/update existing files by default

This is one of the most important pieces.

Many users already have files like `.env`, `.env.local`, or `appsettings.Development.json` with non-azd values that must remain intact.

Merge/update behavior should be the default behavior for file outputs.

We should support merge/update behavior so azd can:

- create the file if it does not exist
- update keys that azd is responsible for
- preserve unrelated user-managed entries
- leave keys alone if they are no longer selected for export

Working model:

```bash
azd env export --out web/.env
```

azd should update only the selected keys/paths rather than overwrite the whole file.

We should design merge behavior so it can reliably update the keys selected for this export and preserve unrelated user-owned content.

### 5. Support dry-run / preview

This should support a dry-run mode so users can preview what would change before writing to disk.

For example:

```bash
azd env export --out web/.env --dry-run
```

At minimum, dry-run should show the resulting content or a useful diff/summary of changes.

### 6. Preserve formatting where reasonable

When exporting into an existing file, azd should preserve formatting to the best of its ability rather than rewriting files aggressively for trivial updates.

For example:

- preserve unrelated entries
- preserve JSON indentation where practical
- avoid unnecessary churn in ordering or quoting when possible

We do not need perfect round-tripping for every edge case in v1, but the feature should avoid creating noisy diffs when a minimal edit would do.

### 7. Keep secret resolution out of scope for v1

This command should export the values currently represented in azd env and should not introduce special secret-resolution behavior in v1.

If we want export-time secret resolution or broader secret referencing semantics, that should be handled in a separate issue across azd rather than embedded only in this command.

## Relationship to auto-export

This issue focuses on the manual export command:

```bash
azd env export --out .env.local
```

That gives users a supported way to export azd values into the app config they use for local development.

Automatic export / sync should be tracked as a separate follow-up feature so we can build on the same file format, subset selection, and merge semantics without overloading this issue.

Related issue: https://github.com/Azure/azure-dev/issues/7544

## Suggested scope boundaries

In scope for this issue:

- A dedicated `azd env export` command
- Exporting to `.env` / dotenv format
- Exporting to generic JSON format
- Selecting subsets of keys via `--include`, with optional target mapping via `--include source=target`
- Excluding keys via repeated `--exclude`
- Filtering support for broader selection patterns
- Merge/update behavior for existing files as the default model
- Dry-run / preview support
- Filename-based format inference
- `--environment` support

Out of scope for this issue:

- Running commands with azd env loaded (covered by `env exec`: https://github.com/Azure/azure-dev/issues/7423)
- Exporting shell-specific `export ...` statements for `eval` / `source`
- Persisting values into the caller's current shell
- Solving `main.parameters.json` env resolution semantics directly
- Secret resolution beyond the current azd env representation
- Automatic export / sync behavior (tracked separately at https://github.com/Azure/azure-dev/issues/7544)

## Open questions

- What should the initial format names be?
- Should filtering support regex, glob, or both?
- For dry-run, should we show a diff, the full rendered result, or both?

## Why this is worth doing

This would give templates and users a much cleaner answer for app config flows:

- better support for "develop my app with azd's provisioned outputs"
- no more copy/paste instructions after provisioning
- fewer custom helper scripts per template
- better support for local-development-first workflows
- safer handling of existing `.env` / config files through merge/update semantics
- a clear separation from shell-export concepts and from `env exec`

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.