//JorgenHoc
← All articles
.NET HostingPillar GuideBy Jorge CalderónUpdated 16 min read

Best .NET Hosting in 2026 — Full Comparison (Azure, AWS, Railway, Fly.io)

A thorough comparison of the top .NET hosting platforms in 2026, including Azure, AWS, Railway, Fly.io, Render, and DigitalOcean — with pricing, DX, and a recommendation matrix.

#azure#dotnet#cloud#devops

Picking the wrong hosting platform for your .NET app is an expensive mistake — both in dollars and developer time. This guide covers every serious option in 2026, with real pricing, real deployment experiences, and a concrete recommendation matrix at the end.

Prices below were verified in August 2026 against each provider's official pricing page (and, for Azure, the Retail Prices API), for US regions unless noted. The app and every deploy config in this guide are real files you can point a CLI at: samples/dotnet-hosting holds one minimal .NET 10 API plus the fly.toml, railway.json, render.yaml, DigitalOcean spec, and Azure Bicep used here, with a smoke test that asserts the app honours a runtime-injected PORT — the part most copied Dockerfiles get wrong (see the Railway section).

☁️ .NET Hosting Comparison 2026
Filter:Sort by:
ProviderFromFreeDockerAuto-scaleSetupDX
🪁
Fly.io
Global low-latency apps, multi-region
$2/mo●●●●●●●●
🚂
Railway
Fastest possible deploy, hobby to startup
$5/mo●●●●●●●●●●
🌊
DigitalOcean Apps
Predictable pricing, developer-friendly
$5/mo●●●●●●●●
🌀
Render.com
Simple deploy, no DevOps overhead
$7/mo●●●●●●●●●
🟠
AWS Elastic Beanstalk
Teams already invested in AWS ecosystem
$8/mo●●○○○●●○○○
☁️
Azure App Service
Enterprises already on Azure / .NET teams
$13/mo●●●●●●●●

Pricing as of Aug 2026. "Setup" = fewer stars → simpler. "DX" = developer experience.

The Contenders

Six platforms worth your attention for .NET workloads:

  • Azure App Service — Microsoft's own PaaS, deepest .NET integration
  • AWS Elastic Beanstalk — Amazon's managed PaaS layer over EC2
  • Railway — modern developer-focused PaaS with minimal config
  • Fly.io — container-first platform with global edge deployment
  • Render.com — Heroku successor with simple pricing
  • DigitalOcean App Platform — straightforward PaaS from a familiar provider

Azure App Service

Overview

Azure App Service is the natural home for .NET apps. Microsoft builds and maintains it, the runtime support is always first-in-class, and the ecosystem integration (Azure SQL, Key Vault, Managed Identity, Application Insights) is unmatched.

Deployment

# Create resource group and App Service plan
az group create --name myapp-rg --location eastus
az appservice plan create --name myapp-plan --resource-group myapp-rg --sku B1 --is-linux
 
# Create the web app targeting .NET 10
az webapp create \
  --name myapp-unique-name \
  --resource-group myapp-rg \
  --plan myapp-plan \
  --runtime "DOTNETCORE:10.0"
 
# Publish, zip, deploy — az webapp deploy wants a zip FILE, not the publish folder;
# pointing --src-path at a directory fails with "not a valid local file path"
dotnet publish -c Release -o ./publish
cd ./publish && zip -r ../app.zip . && cd ..   # Windows: tar.exe -a -cf app.zip -C publish *
az webapp deploy \
  --resource-group myapp-rg \
  --name myapp-unique-name \
  --src-path ./app.zip \
  --type zip

On Windows, do not build the zip with PowerShell's Compress-Archive — it writes zip entries with backslash separators, and the moment your publish output has a subfolder (wwwroot/, runtimes/), Linux App Service fails the deployment with a Kudu rsync error like failed to stat "/home/site/wwwroot/some\file": Invalid argument (22). I hit exactly that deploying this article's sample. Windows ships bsdtar (tar.exe, in System32) which produces correct forward-slash zips. Use * rather than . as the file argument: with ., bsdtar prefixes every entry with ./ — Kudu accepts that zip, but Windows Explorer displays it as empty, which cost me a confused minute.

This is the exact run from deploying the sample, not a dry-run:

PowerShell output of az group create and az appservice plan create: the resource group myapp-rg provisions with provisioningState Succeeded in East US, then the App Service plan myapp-plan is created as a Linux B1 Basic SKU with capacity 1, reserved true, and status Ready.
Steps 1–2: the resource group and the Linux B1 plan, both returning Succeeded.
Output of az webapp create with runtime DOTNETCORE:10.0: the CLI answers that webapp myapp-unique-name was created and suggests deploying with az webapp deploy, listing the default host name myapp-unique-name.azurewebsites.net and its scm deployment host.
Step 3: the web app on the .NET 10 runtime, with its azurewebsites.net host ready before any code was deployed.

Pricing Tiers

Linux plans, East US, August 2026 (Azure Retail Prices API; the portal often shows slightly different rounded figures):

TierPrice/monthRAMvCPUNotes
F1 (Free)$01 GBShared60 min/day CPU limit, no custom-domain SSL
B1 (Basic)~$12–131.75 GB1Always On + custom domains; no autoscale
S1 (Standard)~$691.75 GB1Autoscale, deployment slots
P0v4 (Premium)~$53New Premium v4 entry SKU (meters live since Sep 2025)
P1v3 (Premium)~$1138 GB2Production-grade, zone redundancy available
💡

The B1 tier is the sweet spot for small production apps. When you outgrow it, price Premium v4's P0v4 ($53/month) against S1 ($69/month) before defaulting to Standard — the newer Premium entry SKU undercuts S1 while sitting in the stronger tier.

Deployment Slots

Deployment slots let you run a staging environment and swap it to production with zero downtime:

# Create a staging slot
az webapp deployment slot create \
  --name myapp-unique-name \
  --resource-group myapp-rg \
  --slot staging
 
# Swap staging to production
az webapp deployment slot swap \
  --name myapp-unique-name \
  --resource-group myapp-rg \
  --slot staging \
  --target-slot production

GitHub Actions CI/CD

# .github/workflows/deploy.yml
name: Deploy to Azure App Service
on:
  push:
    branches: [main]
 
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup .NET 10
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'
      - name: Publish
        run: dotnet publish -c Release -o ./publish
      - name: Deploy to Azure
        uses: azure/webapps-deploy@v3
        with:
          app-name: myapp-unique-name
          publish-profile: ${{ secrets.AZURE_PUBLISH_PROFILE }}
          package: ./publish
Azure portal overview of the myapp-unique-name Web App: Status Running, Location East US, Operating System Linux on the myapp-plan B1 plan, Runtime Stack Dotnetcore 10.0, runtime status Healthy, and the Deployment Center showing the last deployment succeeded on Wednesday, August 19.
The result in the portal: Running on Linux B1, .NET 10 runtime healthy, deployment marked successful.

Verdict

Best for: Enterprise .NET apps, teams already in Azure, apps needing Azure SQL, Key Vault, or Managed Identity.

Watch out for: Pricing jumps sharply between B1 and S1. Cold starts on lower tiers.


AWS Elastic Beanstalk

Overview

Elastic Beanstalk is AWS's PaaS abstraction over EC2. You get more control than Azure App Service but also more configuration surface. .NET support is solid via the Windows Server or Linux platforms.

Deployment

# Install EB CLI
pip install awsebcli
 
# Initialize and create environment
eb init myapp --platform "dotnet-core-on-al2023" --region us-east-1
eb create myapp-prod --instance-type t3.small
 
# Deploy
dotnet publish -c Release -o ./publish
cd ./publish
zip -r ../deploy.zip .
eb deploy

Pricing

Elastic Beanstalk itself is free — you pay for the underlying EC2 instances, load balancers, and storage.

On-demand Linux, us-east-1, August 2026:

InstancePrice/month (on-demand)Notes
t3.micro~$7.601 GB RAM, burstable
t3.small~$15Better baseline performance
t3.medium~$302 vCPU, 4 GB RAM

Add ~$16.50/month for an Application Load Balancer if you need it (required for multi-instance), plus LCU usage charges.

Note that AWS's famous 12-month free t3.micro is gone for new accounts: since July 2025 the free tier is credits-based — $100 at signup plus up to $100 more for completing onboarding tasks, expiring after 6 months. Accounts created before that date keep the old 12-month deal.

Autoscaling

// .elasticbeanstalk/env.yaml
option_settings:
  aws:autoscaling:asg:
    MinSize: 1
    MaxSize: 4
  aws:autoscaling:trigger:
    MeasureName: CPUUtilization
    Unit: Percent
    UpperThreshold: 70
    LowerThreshold: 20

Verdict

Best for: Teams already deep in AWS, apps needing fine-grained EC2 control, workloads with variable traffic that need auto-scaling cost optimization.

Watch out for: Steeper learning curve than Azure App Service. Configuration sprawl in .ebextensions.


Railway

Overview

Railway is the highest-DX option in this list. Push code, get a URL. No YAML manifests required for basic use. It runs containers internally and handles routing, TLS, and scaling transparently.

Deployment

# Install Railway CLI
npm install -g @railway/cli
 
# Login and initialize
railway login
railway init
 
# Add a Dockerfile or let Railway auto-detect .NET
# Then deploy
railway up

A minimal Dockerfile for .NET 10:

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app
 
FROM mcr.microsoft.com/dotnet/aspnet:10.0
WORKDIR /app
COPY --from=build /app .
ENTRYPOINT ["dotnet", "MyApp.dll"]

One trap: Railway injects the listen port as a PORT env var at runtime, and the widely copied ENV ASPNETCORE_URLS=http://+:${PORT:-8080} Dockerfile line does not pick it up — Docker resolves ${...} at build time, baking 8080 in. Read PORT in Program.cs instead:

// Program.cs — honour the platform's injected PORT (Railway, Render, Heroku-style)
var port = Environment.GetEnvironmentVariable("PORT");
if (!string.IsNullOrEmpty(port))
{
    builder.WebHost.UseUrls($"http://+:{port}");
}

The sample's smoke test asserts this: the app is started with an injected PORT and must answer on it, locally and inside the container image.

Or use a railway.json for configuration (no startCommand needed — the Dockerfile's ENTRYPOINT covers it):

{
  "$schema": "https://railway.app/railway.schema.json",
  "build": {
    "builder": "DOCKERFILE",
    "dockerfilePath": "Dockerfile"
  },
  "deploy": {
    "healthcheckPath": "/health",
    "healthcheckTimeout": 300,
    "restartPolicyType": "ON_FAILURE"
  }
}

Deployed with exactly that config, Railway's deploy logs show the contract working end to end — container up, listening on the injected port, and the /health probe answering 200 before traffic is routed:

Railway deploy logs: the container starts, ASP.NET Core listens on port 8080, and Railway's health check GET /health returns 200 in about 140 ms.
The sample deploying on Railway: the healthcheckPath from railway.json is probed and returns 200 before the deployment goes live.

Pricing

  • Hobby plan: $5/month, which includes $5 of monthly usage credit
  • Pro plan: $20/month per workspace, includes $20 of usage
  • Usage rates: ~$20 per vCPU-month and ~$10 per GB-of-RAM-month, billed per second ($0.00000772/vCPU-s, $0.00000386/GB-s)
  • Typical small .NET API: fits inside the Hobby plan's included $5
💡

Railway's free trial gives $5 in credits for 30 days with no credit card — enough to evaluate it with a small app before committing.

Environment Variables

railway variables --set "DATABASE_URL=Server=...;Database=...;..." --set "ASPNETCORE_ENVIRONMENT=Production"

Verdict

Best for: Indie developers, startups, side projects, teams who want zero infrastructure management. Excellent for Postgres-backed .NET APIs.

Watch out for: Less mature enterprise features. No SLA for Hobby plan.


Fly.io

Overview

Fly.io runs your containers on hardware in 30+ regions worldwide. It's uniquely suited to latency-sensitive apps that need to run close to users globally.

Deployment

# Install flyctl
curl -L https://fly.io/install.sh | sh
 
# Launch a new app (detects Dockerfile)
fly launch --name myapp --region iad
 
# Deploy
fly deploy

The fly.toml config:

app = "myapp"
primary_region = "iad"
 
[build]
  dockerfile = "Dockerfile"
 
[env]
  ASPNETCORE_ENVIRONMENT = "Production"
  ASPNETCORE_URLS = "http://+:8080"
 
[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 0
 
[[vm]]
  memory = "512mb"
  cpu_kind = "shared"
  cpus = 1

Pricing

Fly discontinued its free allowance in October 2024 — the old "3 free shared VMs" only survives on grandfathered accounts. New organizations get a short free trial (about $5 / 7 days), then pay per second of machine time. Prices vary slightly by region; roughly:

  • shared-cpu-1x 256 MB: ~$2/month running 24/7
  • shared-cpu-1x 512 MB: ~$3.30/month
  • performance-1x 2 GB: ~$32/month (the dedicated-CPU family is now the performance-* SKUs)
  • Volumes: $0.15/GB/month; egress from ~$0.02/GB (no free bandwidth allowance for new orgs)

Multi-Region

# Add regions
fly regions add lhr syd
 
# Scale to have at least 1 machine per region
fly scale count 2 --region lhr
fly scale count 2 --region syd

Secrets Management

fly secrets set DATABASE_URL="..."
fly secrets set JWT_SECRET="..."

Verdict

Best for: Global APIs, latency-sensitive workloads, teams comfortable with containers who want global distribution at reasonable cost.

Watch out for: Auto-stop/start machines add cold-start latency when scaled to zero. More ops-focused than Railway. Managed Postgres starts at $38/month — for a cheap database, pair Fly compute with an external free Postgres instead.


Render.com

Overview

Render is the closest modern Heroku replacement. Simple Git-connected deploys, managed Postgres, and straightforward pricing.

Deployment

# Render deploys from Git automatically
# Just connect your repo in the dashboard and set:
# Build Command: dotnet publish -c Release -o ./publish
# Start Command: dotnet ./publish/MyApp.dll

Or use a Dockerfile (recommended for .NET). This is the sample deploying that way — the whole configuration is one form; the only non-obvious field in a monorepo is Root Directory, which points the Docker build context at the right folder:

Render's New Web Service form for the jorgenhoc-org/dotnet-samples repository: name jorgenhoc-hosting-sample, Language set to Docker, branch main, region Oregon US West, and Root Directory samples/dotnet-hosting for the monorepo.
The entire Render deployment configuration: repo, Docker, branch, and Root Directory for the monorepo — no YAML required.

Pricing

TierPrice/monthRAMvCPU
Free$0512 MB0.1
Starter$7512 MB0.5
Standard$252 GB1
Pro$854 GB2
Render's Instance Type picker with the Free tier selected at $0 per month for 512 MB RAM and 0.1 CPU, alongside paid tiers: Starter $7 for 512 MB and 0.5 CPU, Standard $25 for 2 GB and 1 CPU, Pro $85 for 4 GB and 2 CPU, up to Pro Ultra $450. A note warns that free instances spin down after periods of inactivity.
The instance picker during setup — the same prices as the table above, straight from the dashboard, with the spin-down caveat attached to Free.
⚠️

The Free tier spins down after 15 minutes of inactivity and has a cold start of 30–60 seconds. Not suitable for production APIs that need to be always-on.

Verdict

Best for: Hobby projects, staging environments, teams migrating from Heroku.

Watch out for: Free tier sleep behavior, fewer advanced features than Railway or Fly.io.


DigitalOcean App Platform

Overview

DigitalOcean App Platform offers simple container-based deployments with predictable pricing — no surprise bills from usage-based charging.

Deployment

# Using doctl CLI
doctl apps create --spec app.yaml
# app.yaml
name: myapp
region: nyc
services:
  - name: api
    dockerfile_path: Dockerfile
    github:
      repo: yourorg/yourrepo
      branch: main
      deploy_on_push: true
    instance_size_slug: basic-xxs
    instance_count: 1
    http_port: 8080
    envs:
      - key: ASPNETCORE_ENVIRONMENT
        value: Production

Pricing

DigitalOcean restructured App Platform pricing; containers are now priced per instance size (all on shared vCPUs at the low end):

Price/monthRAMvCPUTransferAutoscaling
$5512 MiB1 shared50 GiBNo (fixed)
$101 GiB1 shared100 GiBNo (fixed)
$121 GiB1 shared150 GiBYes
$252 GiB1 shared200 GiBYes

The free tier covers static sites only — there is no free container option.

Verdict

Best for: Teams who want Heroku-like simplicity with predictable pricing and a familiar provider.

Watch out for: Fewer .NET-specific integrations than Azure. Limited regions compared to Fly.io.


Which Should You Pick? Recommendation Matrix

ScenarioRecommended Platform
Enterprise / Azure shopAzure App Service (S1+)
AWS shop, complex infrastructureAWS Elastic Beanstalk
Indie dev / side project, fast startRailway
Global API, latency mattersFly.io
Migrating from HerokuRender.com (paid tier)
Predictable-cost PaaSDigitalOcean App Platform
Zero budget prototypeRender (free tier, tolerate cold starts) or an Oracle Cloud free VM
Needs managed Postgres, minimal configRailway or Render
Needs Managed Identity, Key VaultAzure App Service
Multi-region active-activeFly.io

Performance Comparison

Cold start times (approximate, shared/burstable VMs, .NET 10 minimal API):

PlatformCold StartNotes
Azure App Service B12–5 sAlways-on option available
AWS EB t3.small1–3 sUsually always-on
Railway3–8 sScales to zero when not in use
Fly.io (auto-stop)2–6 sConfigurable min machines
Render free30–60 sLong sleep cold start
DigitalOcean Basic2–4 sAlways-on
💡

Use Native AOT (available since .NET 8) for apps that need sub-second cold starts on any platform. AOT-compiled .NET apps can start in under 200ms.

Auto-Scaling Comparison

PlatformAuto-ScaleMin-to-Max TimeConfig Complexity
Azure App Service S1Yes (rule-based + HTTP-based)3–5 minMedium
AWS EBYes (EC2 Auto Scaling Groups)3–7 minHigh
RailwayYes (vertical scaling)SecondsLow
Fly.ioYes (machine-based)5–30 sMedium
RenderYes (paid plans)1–3 minLow
DigitalOceanYes (horizontal)1–3 minLow

Free Tier Summary

PlatformFree Tier DetailsProduction-Ready?
AzureF1: 60 CPU-min/day, no custom-domain SSLNo
AWS$100–$200 in credits, expires after 6 months (12-month t3.micro only on pre-2025 accounts)Limited
Railway$5 trial credit, 30 days, no cardTrial only
Fly.ioTrial only — the free VM allowance was discontinued in Oct 2024No
Render1 service, sleeps after 15 min, 750 instance-hours/monthNo
DigitalOceanStatic sites onlyN/A

Final Thoughts

For most .NET developers in 2026, the decision comes down to three options:

  1. Azure App Service if you're in the Microsoft ecosystem or need enterprise features
  2. Railway if you want the fastest path from code to production URL
  3. Fly.io if you need global distribution or cost-efficient always-on containers

The days of "just use Azure because it's .NET" are over. Railway and Fly.io offer compelling DX at lower costs for most workloads. Evaluate based on your team's expertise, scale requirements, and existing cloud commitments.

Every deploy config in this guide is a real file in samples/dotnet-hosting — one minimal API you can deploy to all six platforms unchanged. If budget is the deciding factor, Cheapest Way to Host a .NET App walks the same platforms bottom-up from $0, and the per-platform walkthroughs go deeper: Azure App Service, Railway, Fly.io, and Render.

Further reading

About the author

Jorge Calderón

Software engineer with over a decade building and operating .NET applications in production — EF Core data layers, async-heavy services, and Azure and container deployments. Every benchmark and sample project in these guides is published in a public GitHub repository so you can rerun it yourself.

GitHub profileLinkedIn ↗Benchmarks & sample code

Related articles