Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/frontend/config/sidebar/integrations.topics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,7 @@ export const integrationTopics: StarlightSidebarTopicsUserConfig = {
{ label: 'PowerShell', slug: 'integrations/frameworks/powershell' },
{ label: 'Python', slug: 'integrations/frameworks/python' },
{ label: 'Rust', slug: 'integrations/frameworks/rust' },
{ label: 'WPF and Windows Forms', slug: 'integrations/frameworks/wpf-winforms' },
],
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,3 +254,20 @@ The preceding code:
- A tag is added to the flexible server with a key of `ExampleKey` and a value of `Example value`.

There are many more configuration options available to customize the PostgreSQL resource. For more information, see [Azure.Provisioning customization](/integrations/cloud/azure/customize-resources/#azureprovisioning-customization).

## Database creation after initial deployment

When you call `AddDatabase` on an Azure PostgreSQL resource, Aspire provisions the database during the **first** deployment. On subsequent deployments with `azd up`, only the server-level Bicep is redeployed—databases that already exist are not recreated or deleted.

<Aside type="note">
If a database does not appear after redeployment, verify that the `AddDatabase` call is still present in your AppHost and that the Bicep output in the `infra/` folder is up to date. Run `azd provision` (instead of `azd up`) to force Aspire to re-evaluate the provisioning output.
</Aside>

If you need to add a new database to an existing server, redeploy with the updated AppHost code or manually create the database in the Azure portal or via the PostgreSQL CLI:

```bash title="Bash — Create database manually"
az postgres flexible-server db create \
--resource-group <resource-group> \
--server-name <server-name> \
--database-name <new-database-name>
```
83 changes: 83 additions & 0 deletions src/frontend/src/content/docs/integrations/frameworks/dapr.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,89 @@ app.Run();

For more information on Dapr service invocation, see [Dapr service invocation](https://docs.dapr.io/developing-applications/building-blocks/service-invocation/).

## Configure Dapr state stores

The Aspire Dapr integration supports adding Dapr state store components. Use the `AddDaprStateStore` method to register a state store and reference it from your services:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var stateStore = builder.AddDaprStateStore("statestore");

builder.AddProject<Projects.ExampleProject>("exampleproject")
.WithDaprSidecar()
.WithReference(stateStore);

// After adding all resources, run the app...
```

### Configure an actor state store

To configure a state store as an Actor state store (required by Dapr actors), add the `actorStateStore` metadata entry to your component file. Create a `components` directory in your app host and add a component YAML file:

```yaml title="YAML — components/statestore.yaml"
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: actorStateStore
# Setting actorStateStore to "true" designates this state store
# as the actor state store. Dapr actors require exactly one state
# store to be configured with this flag.
value: "true"
```

Reference the component directory in your AppHost using `WithDaprSidecar` options:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

builder.AddProject<Projects.ActorService>("actorservice")
.WithDaprSidecar(new DaprSidecarOptions
{
ResourcesDirectory = "./components"
});

// After adding all resources, run the app...
```

## Deploy with Azure Container Apps

The Aspire Dapr Community Toolkit integration configures Dapr sidecars for local development. When deploying to Azure Container Apps (ACA), Dapr sidecar settings are part of the container app configuration and must be preserved on each deployment.

<Aside type="caution">
When you redeploy a container app that previously had Dapr enabled, Azure Container Apps does **not** automatically retain Dapr settings from the previous deployment. If Dapr appears disabled in the Azure portal after redeployment, re-enable it by configuring the Dapr settings in the ACA environment or by using `PublishAsAzureContainerApp` with explicit Dapr configuration.
</Aside>

To ensure Dapr settings are preserved on Azure Container Apps deployments, configure the sidecar explicitly using `PublishAsAzureContainerApp`:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

builder.AddProject<Projects.ExampleProject>("exampleproject")
.WithDaprSidecar()
.PublishAsAzureContainerApp((infra, app) =>
{
// Enable Dapr on the container app and set the app ID
app.Configuration.Dapr = new()
{
IsEnabled = true,
AppId = "exampleproject",
AppPort = 8080,
};
});

// After adding all resources, run the app...
```

For more information on customizing Azure Container Apps resources, see [Configure Azure Container Apps](/integrations/cloud/azure/configure-container-apps/).

## See also

- [Dapr documentation](https://docs.dapr.io/)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,94 @@ var viteApp = builder.AddViteApp("vite-app", "./vite-app")

The HTTPS configuration is automatically applied without modifying your `vite.config.js` file. For more information about certificate configuration, see [Certificate configuration](/app-host/certificate-configuration/).

## Pass API URLs to Vite apps

When your Vite app needs to communicate with a backend API, pass the API URL via an environment variable. Vite only exposes variables prefixed with `VITE_` to client-side code.

In your AppHost, expose the API URL to the Vite app using `WithEnvironment`:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var api = builder.AddProject<Projects.ApiService>("api")
.WithExternalHttpEndpoints();

var viteApp = builder.AddViteApp("vite-app", "./vite-app")
.WithReference(api)
.WithEnvironment("VITE_API_BASE_URL", api.GetEndpoint("https"));

// After adding all resources, run the app...
```

In your Vite app, read the variable from `import.meta.env`:

```typescript title="TypeScript — src/api.ts"
const apiBaseUrl = import.meta.env.VITE_API_BASE_URL;

export async function fetchData() {
const response = await fetch(`${apiBaseUrl}/api/data`);
return response.json();
}
```

<Aside type="tip">
`import.meta.env` variables are replaced at **build time** by Vite. For dynamic runtime values (such as a URL that changes per environment), consider using a server-rendered configuration endpoint instead.
</Aside>

## Monorepo and Turborepo patterns

Aspire supports monorepo layouts where multiple JavaScript apps share a single root workspace. Each app is added as a separate resource in the AppHost pointing to its own subdirectory.

### pnpm workspaces

For a pnpm monorepo, install dependencies from the workspace root and reference individual app directories:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var api = builder.AddProject<Projects.ApiService>("api");

// Each app lives in its own subdirectory with its own package.json
var frontend = builder.AddViteApp("frontend", "./apps/frontend")
.WithPnpm()
.WithReference(api);

var dashboard = builder.AddViteApp("dashboard", "./apps/dashboard")
.WithPnpm()
.WithReference(api);

// After adding all resources, run the app...
```

<Aside type="note">
Each app directory must have its own `package.json` with a `dev` script. The `pnpm install` command should be run from the **monorepo root** before starting Aspire, so that the shared `node_modules` are populated.
</Aside>

### Turborepo

Turborepo orchestrates builds across a monorepo. Use a custom run script that delegates to the Turborepo pipeline for a specific app:

```json title="apps/frontend/package.json"
{
"scripts": {
"dev": "turbo run dev --filter=frontend"
}
}
```

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var api = builder.AddProject<Projects.ApiService>("api");

var frontend = builder.AddJavaScriptApp("frontend", "./apps/frontend")
.WithPnpm()
.WithRunScript("dev")
.WithReference(api);

// After adding all resources, run the app...
```

## Production builds

When you publish your application using `aspire deploy`, Aspire automatically:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,70 @@ var python = builder.AddPythonApp("python-api", "../python-app", "main.py")

The connection string will be available as an environment variable in the Python application.

## HTTPS configuration

By default, Python apps run over HTTP in local development. To enable HTTPS, use `WithHttpsEndpoint` and configure the developer certificate in your app host:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var python = builder.AddUvicornApp("python-api", "../python-app", "main:app")
.WithHttpsEndpoint(port: 8443, env: "PORT")
.WithHttpsDeveloperCertificate();

// After adding all resources, run the app...
```

When you call `WithHttpsDeveloperCertificate`, Aspire exports the ASP.NET Core development certificate and injects it into the Python process as environment variables. Read those variables in your Uvicorn startup:

```python title="Python — main.py"
import os
import uvicorn

if __name__ == "__main__":
ssl_keyfile = os.environ.get("ASPNETCORE_Kestrel__Certificates__Default__KeyPath")
ssl_certfile = os.environ.get("ASPNETCORE_Kestrel__Certificates__Default__Path")

uvicorn.run(
"main:app",
host="0.0.0.0",
port=int(os.environ.get("PORT", 8443)),
ssl_keyfile=ssl_keyfile,
ssl_certfile=ssl_certfile,
)
```

<Aside type="note">
HTTPS is primarily needed when your Python service is exposed externally. For internal service-to-service communication within Aspire, HTTP is sufficient and simpler to configure.
</Aside>

## Internal vs. external service exposure

By default, Aspire services are only accessible within the distributed application—they are not exposed to external traffic. To control whether a Python service is reachable from outside the app, use `WithExternalHttpEndpoints`:

```csharp title="C# — AppHost.cs"
var builder = DistributedApplication.CreateBuilder(args);

var internalApi = builder.AddUvicornApp("internal-api", "../internal-api", "main:app")
.WithHttpEndpoint(port: 8001, env: "PORT");
// internalApi is NOT exposed publicly — only reachable by other Aspire resources

var publicApi = builder.AddUvicornApp("public-api", "../public-api", "main:app")
.WithHttpEndpoint(port: 8000, env: "PORT")
.WithExternalHttpEndpoints();
// publicApi IS exposed publicly

builder.AddProject<Projects.WebFrontend>()
.WithReference(internalApi)
.WithReference(publicApi);

// After adding all resources, run the app...
```

<Aside type="tip">
Keep backend Python services (databases, AI inference, internal APIs) unexposed and only expose the services that need to be reachable by browsers or external clients.
</Aside>

## Debugging

The Python hosting integration provides full debugging support in Visual Studio Code:
Expand Down
Loading
Loading