Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds comprehensive Neon Postgres integration to the Aspire Community Toolkit, enabling developers to provision and manage Neon database resources within .NET Aspire applications. The integration includes hosting capabilities with provisioner-based resource management, client helpers for consuming connections, and extensive support for Neon-specific features like branch management, ephemeral branches, branch restoration, and data anonymization.
Changes:
- Added hosting integration (
CommunityToolkit.Aspire.Hosting.Neon) with resource models, builder extensions, provisioner orchestration, and health checks - Added client integration (
CommunityToolkit.Aspire.Neon) for simplified Npgsql registration - Added provisioner project (
CommunityToolkit.Aspire.Neon.Provisioner) with Neon API client and execution logic for attach/provision modes - Added comprehensive test coverage including unit tests, functional tests, and live integration tests
- Updated solution files, workflows, package references, and README
Reviewed changes
Copilot reviewed 45 out of 45 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
tests/CommunityToolkit.Aspire.Neon.Tests/NeonClientPublicApiTests.cs |
Unit tests for client API parameter validation |
tests/CommunityToolkit.Aspire.Hosting.Neon.Tests/NeonFunctionalTests.cs |
Comprehensive functional and integration tests for provisioner and hosting behavior |
tests/CommunityToolkit.Aspire.Hosting.Neon.Tests/AddNeonTests.cs |
Unit tests for hosting API surface and configuration options |
src/CommunityToolkit.Aspire.Neon/AspireNeonExtensions.cs |
Client registration methods for NpgsqlDataSource with health checks |
src/CommunityToolkit.Aspire.Neon.Provisioner/Program.cs |
Provisioner entry point handling attach/provision/suspend/resume operations |
src/CommunityToolkit.Aspire.Neon.Provisioner/Shared/NeonApiClient.cs |
Neon API client with comprehensive HTTP operations and retry logic |
src/CommunityToolkit.Aspire.Hosting.Neon/NeonBuilderExtensions.cs |
Core AddNeon methods, command registration, and provisioner output processing |
src/CommunityToolkit.Aspire.Hosting.Neon/NeonResourceBuilderExtensions.cs |
Fluent API for project, branch, organization, and connection configuration |
src/CommunityToolkit.Aspire.Hosting.Neon/NeonProvisionerProjectTemplate.cs |
Embedded provisioner template materialization logic |
examples/neon/CommunityToolkit.Aspire.Hosting.Neon.AppHost/Program.cs |
Example app host demonstrating Neon integration usage |
README.md |
Updated with Neon integration badges and links |
CommunityToolkit.Aspire.slnx |
Added Neon projects to solution structure |
.github/workflows/tests.yaml |
Added Neon test projects to CI workflow |
|
@dotnet-policy-service agree |
tommasodotNET
left a comment
There was a problem hiding this comment.
overall looks good, but i have doubts about the way provisioning is handled. it looks like it doesn’t follow aspire conventions. i’m not sure how much we want to be tied to core azure integrations, @aaronpowell
src/CommunityToolkit.Aspire.Hosting.Neon/NeonProvisionerMode.cs
Outdated
Show resolved
Hide resolved
src/CommunityToolkit.Aspire.Hosting.Neon/NeonProjectResource.cs
Outdated
Show resolved
Hide resolved
@tommasodotNET thanks for the review. I’ve pushed a second commit addressing the provisioning concerns — would appreciate your thoughts on whether this aligns better with the direction you had in mind. In this update I removed Previously, the default behavior was always attach ( That said, Neon is not modeled or provisioned as an Azure resource in this integration. The goal is not to tie it to Azure semantics, but to follow Aspire’s public conventions where they make sense. One nuance is that Neon (as modeled here) is always an external cloud resource — it never lives locally or necessarily inside the deployment environment. Provisioning (attach or create) always runs because the integration validates the project/branch/database and surfaces connection information in both run and publish modes. I specifically tested this by deploying to a VPS via docker-compose (https://github.com/davidfowl/aspire-ssh-deploy), and Neon is still provisioned even though it does not live on that host. The deployment target (Azure, Kubernetes, Docker, etc.) is independent from where Neon physically resides. For example, a user can deploy their services to Azure while selecting So while the public API now approximates Aspire’s Azure-style Also for clarity: the Neon Azure Native integration has been deprecated and reached end-of-life on January 31, 2026 (https://neon.com/docs/introduction/billing-azure-marketplace). This integration is not related to that model; it targets Neon directly via its API. |
|
@YandyZaldivar thanks for clarifying. i get what you'r saying, which is why i didn't request changes but just posted my comments as such. not sure what the correction direction for this integration should be. the fact that neon should always be provisioned and never run locally is not unheard of. if you microsoft foundry, that can only be deployed on azure by aspire or attached to a pre-deployed resource. that being said, it looks like we are closer to what the average aspire experience is. |
|
Looking at the provisioner part of it, it does make me rather apprehensive on the design, the fact that it does a |
|
Neon as an integration can be modeled in different ways. In fact, it could even make sense to support more than one integration approach for the same resource. That’s why I like to frame this PR as: "within the scope of this integration", and avoid generalizing Neon. I also considered alternatives such as using tooling like neon_local: https://github.com/neondatabase/neon_local, not having a publish mode provisioner, and a few others. @tommasodotNET @aaronpowell Regarding the .NET SDK and dotnet in $PATH, since Aspire itself runs via the .NET SDK, this integration doesn't introduce any additional requirement beyond what is already needed to run the AppHost locally. The provisioner project is embedded and materialized on disk because it's an internal implementation detail of the integration. The intent is to avoid requiring consumers to manage it as a ProjectReference, while still allowing Aspire to treat it as a first-class project resource. In publish mode, the provisioner is emitted as other projects, so in production it behaves like any other containerized resource. The dotnet run path is strictly for local development and dashboard-driven suspend/resume operations. Why not part of the hosting integration?
So the intended flow is:
Happy to discuss further a better design for the provisioner. |
|
Shipping as a series of embedded resources that then have to be hydrated back to disk and then pushed into Aspire is a very inefficient model when you just want something to be modelled as a resource within Aspire.
Yes, so
Resources don't block the main thread of Aspire. Take a look at the Ollama implementation, we have sub-resources that pull images and those are async operations that could take a long time, and it won't block Aspire, only resources that depend on it.
Aspire has teased shipping non-.NET app hosts, so that's probably not a safe assumption to make. Modelling using resources ensures consistency, not dynamically extracting files from an assuembly. |
|
I think there are two valid goals we are trying to satisfy here:
To reconcile these we can:
For advanced scenarios, we could still allow an opt-in mode that emits a physical provisioner container. This would enable restart-driven reconciliation (e.g branch restore, use ephemeral branch, self-healing workflows) without making that the default behavior. For example: var neon = builder.AddNeon(apiKey)...
neon.WithRuntimeProvisioner(); // Explicit call to trigger .AddProject(provisioner)This would:
Let me know if this direction makes more sense or if you have other advice. |
| @@ -0,0 +1,17 @@ | |||
| <Project Sdk="Microsoft.NET.Sdk"> | |||
There was a problem hiding this comment.
I think I'd do this a different way if it were me.
Instead of generating a (basically static) .NET project. If you want this to be a resource in the Aspire app, why don't you create a docker image with this functionality? Then the Neon Hosting library would just .AddContainer("provisioner", "neon-provisioner:latest"), or similar. Then you wouldn't need to generate and build this project everywhere.
Then to reuse the logic in the Hosting package, have a library that is shared between the Hosting integration and the container.
There was a problem hiding this comment.
Yes, but then who hosts the image, who maintains and keeps it sync?
Ideally, aspire supports .AddProject, .AddContainer or something similar accepting a nuget package instead of having to copy sources.
There was a problem hiding this comment.
but then who hosts the image
who maintains and keeps it sync?
I assume you do? Are you going to be the maintainer of the Neon integration?
There was a problem hiding this comment.
Note that in a polyglot apphost, if someone wants to use the Neon integration, now they need to install .NET on their machine, when they don't for other integrations because the code is already compiled.
Closes #398
Adds Neon support to Aspire Community Toolkit with:
What’s included
New packages
CommunityToolkit.Aspire.Hosting.NeonCommunityToolkit.Aspire.NeonCommunityToolkit.Aspire.Neon.ProvisionerHosting integration capabilities
AddNeon(...)resource model with health integration.Attachfor existing resources.Provisionfor create-or-attach workflows.AddDatabase(...).WaitFor(neon)).Client integration capabilities
AddNeonClient(...)) for consuming injected connection strings.Examples and tests
Repo wiring updates
Validation
AddNeonTestsNeonFunctionalTestsPR Checklist
Other information