From bf15479e870cd5a20c7a9901046c0289f1671cc1 Mon Sep 17 00:00:00 2001
From: "aspire-repo-bot[bot]"
<268009190+aspire-repo-bot[bot]@users.noreply.github.com>
Date: Wed, 3 Jun 2026 00:09:53 +0000
Subject: [PATCH 1/5] docs: document proxyless container endpoint on-demand
allocation
Documents the on-demand port allocation behavior for dynamic proxyless
container endpoints introduced in Aspire 13.5 (microsoft/aspire#17851).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
.../docs/fundamentals/networking-overview.mdx | 21 +++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
index 8a3533e1b..650447621 100644
--- a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
+++ b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
@@ -259,6 +259,27 @@ await web.withHttpEndpoint({ targetPort: 80, isProxied: false });
+### Resolving proxyless container endpoints before container creation
+
+Proxyless container endpoints normally defer host port assignment until DCP creates the container. This means that if you reference an endpoint in a `WithEnvironment` callback or similar configuration that runs before the container is fully built, the port may not yet be available, which can cause deadlocks or failures.
+
+Starting in Aspire 13.5, Aspire supports on-demand port allocation for dynamic proxyless container endpoints. When your AppHost code references a proxyless container endpoint before the container is created — for example, to expose the container's own port number as an environment variable — Aspire commits the `targetPort` as a fallback host port and makes it available immediately. Once the container's ports are finalized, normal DCP-based host port assignment takes over for any subsequent endpoint resolution.
+
+This lets you write patterns like the following, where a container exposes its own public port in an environment variable:
+
+```csharp title="AppHost.cs"
+var database = builder.AddContainer("database", "image")
+ .WithEndpoint(name: "tcp", targetPort: 5432, isProxied: false);
+
+database.WithEnvironment("PUBLIC_PORT", database.GetEndpoint("tcp").Property(EndpointProperty.Port));
+```
+
+In this example, `PUBLIC_PORT` is set to the endpoint's port before the container is created. Because the endpoint is proxyless and has a `targetPort` of `5432`, Aspire uses `5432` as the fallback host port so the value is available immediately.
+
+:::note
+If the endpoint is not referenced before container creation, DCP still assigns the host port dynamically. On-demand allocation only activates when a proxyless container endpoint is explicitly resolved before container creation completes.
+:::
+
## Omit the host port
For proxied endpoints, when you omit the host port, Aspire generates a random port for both host and service port. This is useful when you want to avoid port conflicts and don't care about the host or service port. Consider the following code:
From aaab7dd51c3699df7b96dd2b50b69185dc1a27d7 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 12 Jun 2026 22:29:20 +0000
Subject: [PATCH 2/5] docs: update proxyless endpoint port allocation
Co-authored-by: danegsta <50252651+danegsta@users.noreply.github.com>
---
.../docs/fundamentals/networking-overview.mdx | 35 +++++++++++++++----
1 file changed, 29 insertions(+), 6 deletions(-)
diff --git a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
index 650447621..9a5579903 100644
--- a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
+++ b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
@@ -259,13 +259,16 @@ await web.withHttpEndpoint({ targetPort: 80, isProxied: false });
-### Resolving proxyless container endpoints before container creation
+### Allocate ports for dynamic proxyless endpoints
-Proxyless container endpoints normally defer host port assignment until DCP creates the container. This means that if you reference an endpoint in a `WithEnvironment` callback or similar configuration that runs before the container is fully built, the port may not yet be available, which can cause deadlocks or failures.
+Proxyless endpoints can define a `targetPort` without defining a public host `port`. Starting in Aspire 13.5, Aspire allocates a public host port for each dynamic proxyless endpoint before workload resources are created. The allocated port is then available to configuration that resolves endpoint properties, such as `GetEndpoint(...).Property(EndpointProperty.Port)`.
-Starting in Aspire 13.5, Aspire supports on-demand port allocation for dynamic proxyless container endpoints. When your AppHost code references a proxyless container endpoint before the container is created — for example, to expose the container's own port number as an environment variable — Aspire commits the `targetPort` as a fallback host port and makes it available immediately. Once the container's ports are finalized, normal DCP-based host port assignment takes over for any subsequent endpoint resolution.
+If you set `port`, Aspire uses that value as the public host port. If you omit `port`, Aspire allocates one from the proxyless endpoint port range. The default range is `10000-32767`, and you can override it with the `ASPIRE_PROXYLESS_ENDPOINT_PORT_RANGE` environment variable in `start-end` format.
-This lets you write patterns like the following, where a container exposes its own public port in an environment variable:
+This lets you write patterns like the following, where a container exposes its allocated public port in an environment variable:
+
+
+
```csharp title="AppHost.cs"
var database = builder.AddContainer("database", "image")
@@ -274,10 +277,30 @@ var database = builder.AddContainer("database", "image")
database.WithEnvironment("PUBLIC_PORT", database.GetEndpoint("tcp").Property(EndpointProperty.Port));
```
-In this example, `PUBLIC_PORT` is set to the endpoint's port before the container is created. Because the endpoint is proxyless and has a `targetPort` of `5432`, Aspire uses `5432` as the fallback host port so the value is available immediately.
+
+
+
+```typescript title="apphost.mts" twoslash
+import { EndpointProperty, createBuilder } from './.aspire/modules/aspire.mjs';
+
+const builder = await createBuilder();
+
+const database = await builder.addContainer('database', {
+ image: 'image',
+ tag: 'latest',
+});
+await database.withEndpoint({ name: 'tcp', targetPort: 5432, isProxied: false });
+
+await database.withEnvironment('PUBLIC_PORT', database.getEndpoint('tcp').property(EndpointProperty.Port));
+```
+
+
+
+
+In this example, `PUBLIC_PORT` is set to the endpoint's allocated public host port before the container is created. Because the endpoint is proxyless and doesn't specify `port`, Aspire allocates a port from the proxyless endpoint port range.
:::note
-If the endpoint is not referenced before container creation, DCP still assigns the host port dynamically. On-demand allocation only activates when a proxyless container endpoint is explicitly resolved before container creation completes.
+For persistent resources, Aspire persists allocated proxyless endpoint ports in user secrets and reuses them on later AppHost runs.
:::
## Omit the host port
From 71af92ddfc6c708a646441ed45faafb71468c8b3 Mon Sep 17 00:00:00 2001
From: David Negstad
Date: Mon, 29 Jun 2026 15:37:17 -0700
Subject: [PATCH 3/5] docs: align proxyless port allocation docs
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
---
.../src/content/docs/app-host/resource-lifetimes.mdx | 9 +++++++--
.../docs/fundamentals/networking-overview.mdx | 12 ++++++------
.../src/content/docs/whats-new/aspire-13-5.mdx | 3 +++
3 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/src/frontend/src/content/docs/app-host/resource-lifetimes.mdx b/src/frontend/src/content/docs/app-host/resource-lifetimes.mdx
index 183e8dabc..854913c50 100644
--- a/src/frontend/src/content/docs/app-host/resource-lifetimes.mdx
+++ b/src/frontend/src/content/docs/app-host/resource-lifetimes.mdx
@@ -5,6 +5,7 @@ description: Learn how session, persistent, resource-scoped, and parent-process
import { Tabs, TabItem } from '@astrojs/starlight/components';
import { Image } from 'astro:assets';
+import LearnMore from '@components/LearnMore.astro';
import persistentContainer from '@assets/whats-new/aspire-9/persistent-container.png';
import persistentContainerDocker from '@assets/whats-new/aspire-9/persistent-container-docker-desktop.png';
@@ -40,7 +41,11 @@ Persistent resources are automatically recreated when the AppHost detects meanin
Persistent containers use proxied endpoints by default, just like session containers. The proxy runs only while the AppHost is running, so the proxy address isn't reachable after the AppHost stops. Persistent executables and projects default to proxyless endpoints so their direct addresses stay stable and reachable even after the AppHost stops.
-You can still configure endpoint proxy behavior explicitly on any persistent resource. Set `isProxied: false` on an individual endpoint, or call `WithEndpointProxySupport(false)` to make every endpoint on a resource proxyless. Persistent executable endpoints must have a concrete `port` or `targetPort`; automatically persisted random executable ports aren't supported. For proxyless container endpoints with only a `targetPort`, Aspire immediately uses the target port as the allocated host port.
+You can still configure endpoint proxy behavior explicitly on any persistent resource. Set `isProxied: false` on an individual endpoint, or call `WithEndpointProxySupport(false)` to make every endpoint on a resource proxyless. When a proxyless endpoint doesn't specify a public `port`, Aspire allocates one before the resource is created. For persistent resources, Aspire stores the allocated port in user secrets when user secrets are available and reuses it on later AppHost runs.
+
+
+ For more information, see [Allocate ports for dynamic proxyless endpoints](/fundamentals/networking-overview/#allocate-ports-for-dynamic-proxyless-endpoints).
+
:::danger[Persistent container ≠ persistent data]
Persistent container lifetime doesn't guarantee data durability. For details, see [Container lifetime vs. data durability](#container-lifetime-vs-data-durability).
@@ -157,7 +162,7 @@ await builder.build().run();
-Configure a concrete `port` or `targetPort` for persistent executable endpoints; automatically persisted random executable ports aren't supported.
+The preceding example configures a concrete `port` so the endpoint address is explicit. If you omit the public `port`, Aspire allocates one before the executable starts and reuses it from user secrets on later AppHost runs when user secrets are available.
## Configure a persistent project
diff --git a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
index 37148c6fb..c8d983d3d 100644
--- a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
+++ b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
@@ -55,7 +55,7 @@ The inner loop is the process of developing and testing your app locally before
- **Endpoints/Endpoint configurations**: Endpoints are the connections between your app and the services it depends on, such as databases, message queues, or APIs. Endpoints provide information such as the service name, host port, scheme, and environment variable. Aspire can create endpoints automatically from resource configuration, and you can also add them explicitly by calling `WithEndpoint`.
- **Proxies**: Aspire automatically launches a proxy for each proxied service binding you add to your app, and assigns a port for the proxy to listen on. The proxy then forwards the requests to the port that your app listens on, which might be different from the proxy port. This way, you can avoid port conflicts and access your app and services using consistent and predictable URLs.
-- **Proxyless endpoints**: Endpoints with `IsProxied` set to `false` connect directly to the resource instead of routing through an Aspire-managed proxy. Starting in Aspire 13.4, endpoints on persistent executables and projects are proxyless by default. Persistent containers use proxied endpoints by default, the same as session containers. Proxyless endpoints must specify a target port so Aspire knows which port the resource listens on.
+- **Proxyless endpoints**: Endpoints with `IsProxied` set to `false` connect directly to the resource instead of routing through an Aspire-managed proxy. Starting in Aspire 13.4, endpoints on persistent executables and projects are proxyless by default. Persistent containers use proxied endpoints by default, the same as session containers. Proxyless container endpoints must specify a target port so Aspire knows which port the container listens on.
- **Container networks**: Aspire creates and manages dedicated networks for container resources so containers can discover and communicate with each other during local development.
## How endpoints work
@@ -232,9 +232,9 @@ Most endpoints are proxied by default. A proxyless endpoint skips the Aspire-man
Starting in Aspire 13.4, endpoints on persistent executables and projects are proxyless by default. This lets the persistent resource keep using its direct endpoint across AppHost runs instead of depending on a new proxy instance each time. This also ensures that the ports your service is reachable on stay stable whether the AppHost is running or not. Persistent containers use proxied endpoints by default, the same as session containers, so integrations that depend on endpoint allocation before startup continue to work.
-For proxyless container endpoints, Aspire resolves the host port immediately when only a `targetPort` is specified — there is no deferred allocation. For example, `.WithEndpoint(targetPort: 6379, isProxied: false)` allocates host port `6379` right away.
+For proxyless container endpoints, Aspire resolves the host port before creating the container when only a `targetPort` is specified. For example, `.WithEndpoint(targetPort: 6379, isProxied: false)` allocates a public host port from the proxyless endpoint port range and maps it to target port `6379`.
-Because there's no proxy to listen on one port and forward to another, every proxyless endpoint must include a target port. The target port tells Aspire which port the resource listens on. You can also set `port` when you need a specific host port, but `targetPort` is still required for proxyless endpoints.
+Because there's no proxy to listen on one port and forward to another, every proxyless container endpoint must include a target port. The target port tells Aspire which port the container listens on. You can also set `port` when you need a specific host port, but `targetPort` is still required for proxyless container endpoints.
@@ -264,9 +264,9 @@ await web.withHttpEndpoint({ targetPort: 80, isProxied: false });
### Allocate ports for dynamic proxyless endpoints
-Proxyless endpoints can define a `targetPort` without defining a public host `port`. Starting in Aspire 13.5, Aspire allocates a public host port for each dynamic proxyless endpoint before workload resources are created. The allocated port is then available to configuration that resolves endpoint properties, such as `GetEndpoint(...).Property(EndpointProperty.Port)`.
+Proxyless endpoints can omit the public host `port`. Starting in Aspire 13.5, Aspire allocates a public host port for each dynamic proxyless endpoint before workload resources are created. The allocated port is then available to configuration that resolves endpoint properties, such as `GetEndpoint(...).Property(EndpointProperty.Port)`.
-If you set `port`, Aspire uses that value as the public host port. If you omit `port`, Aspire allocates one from the proxyless endpoint port range. The default range is `10000-32767`, and you can override it with the `ASPIRE_PROXYLESS_ENDPOINT_PORT_RANGE` environment variable in `start-end` format.
+If you set `port`, Aspire uses that value as the public host port. If you omit `port`, Aspire allocates one from the proxyless endpoint port range. The default range is `10000-32767`, and you can override it with the `ASPIRE_PROXYLESS_ENDPOINT_PORT_RANGE` environment variable in `start-end` format. Container endpoints still require `targetPort` so Aspire knows which port inside the container receives traffic.
This lets you write patterns like the following, where a container exposes its allocated public port in an environment variable:
@@ -303,7 +303,7 @@ await database.withEnvironment('PUBLIC_PORT', database.getEndpoint('tcp').proper
In this example, `PUBLIC_PORT` is set to the endpoint's allocated public host port before the container is created. Because the endpoint is proxyless and doesn't specify `port`, Aspire allocates a port from the proxyless endpoint port range.
:::note
-For persistent resources, Aspire persists allocated proxyless endpoint ports in user secrets and reuses them on later AppHost runs.
+For persistent resources, Aspire stores allocated proxyless endpoint ports in user secrets when user secrets are available and reuses them on later AppHost runs. If Aspire can't persist the allocated port, configure a fixed public `port` or use a proxied endpoint to avoid recreating the persistent resource on each run.
:::
## Omit the host port
diff --git a/src/frontend/src/content/docs/whats-new/aspire-13-5.mdx b/src/frontend/src/content/docs/whats-new/aspire-13-5.mdx
index 080769dc7..36efbeca9 100644
--- a/src/frontend/src/content/docs/whats-new/aspire-13-5.mdx
+++ b/src/frontend/src/content/docs/whats-new/aspire-13-5.mdx
@@ -45,6 +45,7 @@ This release introduces:
- **VS Code extension renamed to "Aspire"** and rebranded for clarity on the Marketplace.
- **AppHost discovery efficiency** in VS Code respects exclusion settings and debounces file changes to reduce background scanning.
- **Foundry Local integration CLI update** now uses the foundry CLI for lifecycle management, requiring foundry 1.1.0+.
+- **Proxyless endpoint port allocation** assigns dynamic public host ports before resources are created, so endpoint property references resolve consistently.
- …and much more.
## 🆙 Upgrade to Aspire 13.5
@@ -200,6 +201,8 @@ The following breaking changes are included in Aspire 13.5:
4. **GitHub Models integration deprecated**: The GitHub Models service is no longer available to new customers, so the `Aspire.Hosting.GitHub.Models` integration is sunset as of Aspire 13.5. All public APIs are marked `[Obsolete]`, and the package no longer appears in `aspire add` output. One final obsolete release will ship on NuGet, and the package will be removed entirely in a future version. Migrate to the [Azure AI Foundry integration](/integrations/cloud/azure/azure-ai-foundry/azure-ai-foundry-get-started/) instead. See [microsoft/aspire#18402](https://github.com/microsoft/aspire/issues/18402) for details.
+5. **Proxyless endpoint port allocation timing changed**: Proxyless endpoints without an explicit public `port` now receive one during service preparation, before workload resources are created. Executable proxyless endpoints that previously failed without a public port, and container proxyless endpoints that expected the public port to be assigned later during container startup, should expect Aspire to assign the port earlier. The default allocation range is `10000-32767` and can be overridden with `ASPIRE_PROXYLESS_ENDPOINT_PORT_RANGE=start-end`. Persistent resources reuse allocated ports from user secrets when available.
+
From 2b434c288aa17c6c7b833c67f96213ca31db22e3 Mon Sep 17 00:00:00 2001
From: David Negstad
Date: Mon, 29 Jun 2026 15:51:08 -0700
Subject: [PATCH 4/5] docs: clarify proxyless container port wording
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
---
.../src/content/docs/fundamentals/networking-overview.mdx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
index c8d983d3d..7f92c77e0 100644
--- a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
+++ b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
@@ -55,7 +55,7 @@ The inner loop is the process of developing and testing your app locally before
- **Endpoints/Endpoint configurations**: Endpoints are the connections between your app and the services it depends on, such as databases, message queues, or APIs. Endpoints provide information such as the service name, host port, scheme, and environment variable. Aspire can create endpoints automatically from resource configuration, and you can also add them explicitly by calling `WithEndpoint`.
- **Proxies**: Aspire automatically launches a proxy for each proxied service binding you add to your app, and assigns a port for the proxy to listen on. The proxy then forwards the requests to the port that your app listens on, which might be different from the proxy port. This way, you can avoid port conflicts and access your app and services using consistent and predictable URLs.
-- **Proxyless endpoints**: Endpoints with `IsProxied` set to `false` connect directly to the resource instead of routing through an Aspire-managed proxy. Starting in Aspire 13.4, endpoints on persistent executables and projects are proxyless by default. Persistent containers use proxied endpoints by default, the same as session containers. Proxyless container endpoints must specify a target port so Aspire knows which port the container listens on.
+- **Proxyless endpoints**: Endpoints with `IsProxied` set to `false` connect directly to the resource instead of routing through an Aspire-managed proxy. Starting in Aspire 13.4, endpoints on persistent executables and projects are proxyless by default. Persistent containers use proxied endpoints by default, the same as session containers.
- **Container networks**: Aspire creates and manages dedicated networks for container resources so containers can discover and communicate with each other during local development.
## How endpoints work
@@ -234,7 +234,7 @@ Starting in Aspire 13.4, endpoints on persistent executables and projects are pr
For proxyless container endpoints, Aspire resolves the host port before creating the container when only a `targetPort` is specified. For example, `.WithEndpoint(targetPort: 6379, isProxied: false)` allocates a public host port from the proxyless endpoint port range and maps it to target port `6379`.
-Because there's no proxy to listen on one port and forward to another, every proxyless container endpoint must include a target port. The target port tells Aspire which port the container listens on. You can also set `port` when you need a specific host port, but `targetPort` is still required for proxyless container endpoints.
+For containers, `targetPort` always identifies the port inside the container that receives traffic. Proxyless endpoints change how the public host port is selected: set `port` when you need a specific host port, or omit it to let Aspire allocate one from the proxyless endpoint port range.
From 3f2af2296235abd13f190701dc2b5ba9a0e47cda Mon Sep 17 00:00:00 2001
From: David Negstad
Date: Mon, 29 Jun 2026 15:54:13 -0700
Subject: [PATCH 5/5] docs: remove redundant proxyless port text
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
---
.../src/content/docs/fundamentals/networking-overview.mdx | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
index 7f92c77e0..148806a87 100644
--- a/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
+++ b/src/frontend/src/content/docs/fundamentals/networking-overview.mdx
@@ -232,9 +232,7 @@ Most endpoints are proxied by default. A proxyless endpoint skips the Aspire-man
Starting in Aspire 13.4, endpoints on persistent executables and projects are proxyless by default. This lets the persistent resource keep using its direct endpoint across AppHost runs instead of depending on a new proxy instance each time. This also ensures that the ports your service is reachable on stay stable whether the AppHost is running or not. Persistent containers use proxied endpoints by default, the same as session containers, so integrations that depend on endpoint allocation before startup continue to work.
-For proxyless container endpoints, Aspire resolves the host port before creating the container when only a `targetPort` is specified. For example, `.WithEndpoint(targetPort: 6379, isProxied: false)` allocates a public host port from the proxyless endpoint port range and maps it to target port `6379`.
-
-For containers, `targetPort` always identifies the port inside the container that receives traffic. Proxyless endpoints change how the public host port is selected: set `port` when you need a specific host port, or omit it to let Aspire allocate one from the proxyless endpoint port range.
+The following example configures a proxyless HTTP endpoint for an nginx container: