PinguApps.Aspire.Hosting.Railway
1.1.1
dotnet add package PinguApps.Aspire.Hosting.Railway --version 1.1.1
NuGet\Install-Package PinguApps.Aspire.Hosting.Railway -Version 1.1.1
<PackageReference Include="PinguApps.Aspire.Hosting.Railway" Version="1.1.1" />
<PackageVersion Include="PinguApps.Aspire.Hosting.Railway" Version="1.1.1" />
<PackageReference Include="PinguApps.Aspire.Hosting.Railway" />
paket add PinguApps.Aspire.Hosting.Railway --version 1.1.1
#r "nuget: PinguApps.Aspire.Hosting.Railway, 1.1.1"
#:package PinguApps.Aspire.Hosting.Railway@1.1.1
#addin nuget:?package=PinguApps.Aspire.Hosting.Railway&version=1.1.1
#tool nuget:?package=PinguApps.Aspire.Hosting.Railway&version=1.1.1
PinguApps.Aspire.Hosting.Railway
Deploy normal Aspire projects and containers into a pre-created, site-owned Railway environment. Local development stays unchanged. Retained images deploy without building or pushing containers. Opt-in source uploads let Railway build and retain containers without an external private-registry pull credential.
Install
Requires .NET 10 and Aspire 13.6.0.
dotnet add package PinguApps.Aspire.Hosting.Railway --version 1.0.0
C# AppHost
using Aspire.Hosting.Railway;
var web = builder.AddProject<Projects.Web>("web");
if (builder.ExecutionContext.IsPublishMode)
{
var target = builder.AddRailwayTarget("railway",
builder.AddParameter("railway-project-id", Current("Parameters__railway_project_id")),
builder.AddParameter("railway-environment-id", Current("Parameters__railway_environment_id")),
builder.AddParameter("railway-api-token", Current("Parameters__railway_api_token"), secret: true),
builder.AddParameter("site-key", Current("Parameters__site_key")));
web.PublishToRailway(target, options =>
{
options.Image = release.WebImage; // ghcr.io/...@sha256:...
options.Port = 8080;
options.PublicDomain = true;
options.HealthCheckPath = "/health";
options.Region = "europe-west4-drams3a";
options.MemoryGB = 1;
options.VCpus = 1;
options.SealedVariables.Add("ConnectionStrings__database");
});
}
string Current(string name) => Environment.GetEnvironmentVariable(name)
?? throw new InvalidOperationException($"Missing deployment input: {name}");
Before deployment, set the environment's shared PINGUAPPS_SITE_KEY to its allocation record's site key. The package never creates projects, environments, or allocation records. Default authentication uses an environment-scoped project token and validates its exact scope and the live site marker before writes.
Supply current destination and credential parameters on every deployment. Aspire itself can retain parameter values in deployment state; do not rely on cached credentials after rotation. The C# guide shows explicit current inputs. Account/workspace Bearer mode additionally requires the recorded project name and workspace ID.
aspire deploy --non-interactive
aspire deploy --non-interactive --list-steps
The read-only target plan validates all declared services before provider mutations. Then each service waits for provider prerequisites and explicit release dependencies, resolves runtime bindings, applies changes, and verifies the exact deployment ID.
TypeScript AppHost
{
"appHost": { "path": "apphost.mts", "language": "typescript/nodejs" },
"sdk": { "version": "13.6.0" },
"packages": { "PinguApps.Aspire.Hosting.Railway": "1.0.0" }
}
import { createBuilder, railwayOwnershipMode } from "./.aspire/modules/aspire.mjs";
const builder = await createBuilder();
let web = await builder.addContainer("web", "example/web");
if (await builder.executionContext().isPublishMode()) {
const project = await builder.addParameter("railway-project-id", { value: current("Parameters__railway_project_id") });
const environment = await builder.addParameter("railway-environment-id", { value: current("Parameters__railway_environment_id") });
const token = await builder.addParameter("railway-api-token", { value: current("Parameters__railway_api_token"), secret: true });
const site = await builder.addParameter("site-key", { value: current("Parameters__site_key") });
const target = await builder.addRailwayTarget("railway", project, environment, token, site);
web = await web.publishToRailway(target, {
image: "ghcr.io/example/web@sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
ownershipMode: railwayOwnershipMode.createOrAdopt,
port: 8080, publicDomain: true, healthCheckPath: "/health"
});
}
const app = await builder.build();
await app.run();
function current(name: string): string {
const value = process.env[name];
if (!value) throw new Error(`Missing deployment input: ${name}`);
return value;
}
The packed fixture validates actual NuGet-generated exports. Explicitly declare this package alongside companion packages so the shared target API is generated.
Ownership and repeatability
CreateOnly: create a missing service; later deployments reuse its recorded identity. Do not adopt unrelated pre-existing infrastructure.ExistingOnly: require a proven existing service; never create one.CreateOrAdopt: create a missing service or adopt a service marked for the same site/resource. Unmarked adoption additionally requires an explicitExistingServiceId.- Cached IDs remain bound to site, project, environment, and name. Missing or replaced identities fail safely.
- Volume identity, mount, region, and unexpected public-domain drift require operator reconciliation. Infrastructure is never deleted automatically.
- Explicit region aliases configure Railway's provider region before volume creation. New volumes must prove their service, mount and region before deployment; incomplete creation metadata is polled within the shared deployment deadline, including in-flight reads, while known mismatches fail. A volume-confirmation timeout retains recorded identities and stops the remaining configuration and deployment stages. The completed deployment must retain the requested single region and replica count. Existing volume region drift still requires operator migration.
- Pending application state allows retries without duplicate resources or skipping an unfinished deployment.
Runtime and release configuration
Use normal WithEnvironment, WithReference, and parameter expressions. Published endpoints resolve to Railway private hostnames and container ports. DeploymentDependsOn and WithRailwayDeploymentDependency gate dependent deployments, including finite jobs. Workers get no public domain unless requested.
Ordinary services must reach Railway SUCCESS. Finite execution additionally must stop with every instance EXITED; a running deployment is insufficient. Failure, removal, or a timeout prevents downstream deployment. Cron workloads use Never restart and must exit. The Jobs companion package supplies workload-specific APIs and cron validation.
Private GHCR images need Railway private-registry support (currently a Pro feature) and a narrowly scoped pull credential:
web.WithRailwayRegistryCredentials(
builder.AddParameter("ghcr-user"),
builder.AddParameter("ghcr-pull-token", secret: true));
Pull credentials go only to Railway's control plane. Variables listed in SealedVariables become write-only runtime secrets. State stores keyed desired-value fingerprints, never their values or registry passwords. Infrastructure credentials in workload configuration cause refusal.
For deployments without private-registry pull credentials, select options.Build = new RailwayBuildOptions { ContextPath = "../..", DockerfilePath = "src/Web/Dockerfile" }. Railway builds and retains that service's container; aspire deploy performs the upload internally. The deployment machine needs Railway CLI 5.63.1 or later. See source builds for C#/TypeScript examples, upload exclusions, job ordering, and retention limits. Existing image-based publishing remains the default.
Development and release
dotnet test Aspire.Hosting.Railway.slnx -c Release
pwsh ./eng/Test-AspireVersionPins.ps1
pwsh ./eng/Validate-TypeScriptAppHostPackage.ps1
Workflows follow the existing integration repositories: pinned actions, release drafting, NuGet OIDC publishing, symbols, and the packed TypeScript gate. Configure Blacksmith access and NUGET_USER; register the GitHub repository/workflow as a NuGet trusted publisher. No persistent NuGet API key is required.
See configuration, deployment behavior, security, and live validation.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Aspire.Hosting (>= 13.6.0)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on PinguApps.Aspire.Hosting.Railway:
| Package | Downloads |
|---|---|
|
PinguApps.Aspire.Hosting.Railway.Jobs
Finite release jobs and scheduled container jobs for Aspire Railway deployments. |
|
|
PinguApps.Aspire.Hosting.RabbitMQ.Railway
Deploy standard Aspire RabbitMQ resources to Railway with private AMQP and authenticated HTTPS management. |
|
|
PinguApps.Aspire.Hosting.Dashboard.Railway
Authenticated standalone Aspire dashboard publishing for Railway. |
GitHub repositories
This package is not used by any popular GitHub repositories.