Full Stack Deployment

Deploy a .NET API backend and JavaScript frontend to different hosting platforms.

Overview

Modern web applications often have separate backend and frontend codebases deployed to different platforms. This example shows how to build and deploy a .NET API to Azure App Service and a React/Vue frontend to Cloudflare Pages.

Project Structure

my-app/
├── src/
│   └── Api/
│       └── Api.csproj          # .NET Web API
├── frontend/
│   ├── package.json            # React/Vue/Astro frontend
│   └── src/
├── tests/
│   └── Api.Tests/
└── build.csando

Basic Full Stack Build

var deploy = DefineProfile("deploy");

// Project references
var api = Dotnet.Project("./src/Api/Api.csproj");
var tests = Dotnet.Project("./tests/Api.Tests/Api.Tests.csproj");
var frontend = Directory("./frontend");

// === Backend ===
Dotnet.SdkInstall();
Dotnet.Restore(api);
Dotnet.Build(api);
Dotnet.Test(tests);

Dotnet.Publish(api, o => o
    .WithConfiguration(Configuration.Release)
    .Output(Root / "publish" / "api"));

// === Frontend ===
Node.Install();
Npm.Ci(frontend);
Npm.Build(frontend);

if (deploy)
{
    // Deploy API to Azure
    Azure.EnsureAuthenticated();
    AppService.DeployZip("my-api", Root / "publish" / "api");

    // Deploy frontend to Cloudflare
    Cloudflare.EnsureAuthenticated();
    Cloudflare.PagesDeploy(frontend / "dist", "my-frontend");
    Cloudflare.PurgeCache("example.com");

    Log.Info("Full stack deployment complete!");
}

With Database Migrations

Include EF Core migrations before API deployment:

var deploy = DefineProfile("deploy");

var api = Dotnet.Project("./src/Api/Api.csproj");
var frontend = Directory("./frontend");

// Build backend
Dotnet.SdkInstall();
Dotnet.Restore(api);
Dotnet.Build(api);
Dotnet.Publish(api, o => o
    .WithConfiguration(Configuration.Release)
    .Output(Root / "publish" / "api"));

// Build frontend
Node.Install();
Npm.Ci(frontend);
Npm.Build(frontend);

if (deploy)
{
    Azure.EnsureAuthenticated();

    // 1. Run database migrations first
    var dbContext = Ef.DbContextFrom(api, "AppDbContext");
    Ef.DatabaseUpdate(dbContext, Env("CONNECTION_STRING"));
    Log.Info("Database migrations applied");

    // 2. Deploy API with slot swap
    AppService.DeployWithSwap("my-api", Root / "publish" / "api", "staging");
    Log.Info("API deployed");

    // 3. Deploy frontend
    Cloudflare.EnsureAuthenticated();
    Cloudflare.PagesDeploy(frontend / "dist", "my-frontend");
    Cloudflare.PurgeCache("example.com");
    Log.Info("Frontend deployed");
}

Separate Deployment Profiles

Deploy frontend and backend independently:

var deployApi = DefineProfile("deploy-api");
var deployFrontend = DefineProfile("deploy-frontend");
var deployAll = DefineProfile("deploy");

var api = Dotnet.Project("./src/Api/Api.csproj");
var frontend = Directory("./frontend");

// Always build everything
Dotnet.SdkInstall();
Dotnet.Restore(api);
Dotnet.Build(api);
Dotnet.Publish(api, o => o
    .WithConfiguration(Configuration.Release)
    .Output(Root / "publish" / "api"));

Node.Install();
Npm.Ci(frontend);
Npm.Build(frontend);

// Deploy API
if (deployApi || deployAll)
{
    Azure.EnsureAuthenticated();
    AppService.DeployWithSwap("my-api", Root / "publish" / "api", "staging");
    Log.Info("API deployed");
}

// Deploy frontend
if (deployFrontend || deployAll)
{
    Cloudflare.EnsureAuthenticated();
    Cloudflare.PagesDeploy(frontend / "dist", "my-frontend");
    Cloudflare.PurgeCache("example.com");
    Log.Info("Frontend deployed");
}

Usage:

# Build only
ando

# Deploy just the API
ando -p deploy-api

# Deploy just the frontend
ando -p deploy-frontend

# Deploy everything
ando -p deploy

With Environment-Specific Builds

Configure frontend for different environments:

var deploy = DefineProfile("deploy");
var production = DefineProfile("production");

var api = Dotnet.Project("./src/Api/Api.csproj");
var frontend = Directory("./frontend");

// Build backend
Dotnet.SdkInstall();
Dotnet.Restore(api);
Dotnet.Build(api);

// Build frontend with environment-specific config
Node.Install();
Npm.Ci(frontend);

if (production)
{
    // Production build with optimizations
    Npm.Run(frontend, "build:production");
}
else
{
    // Staging/development build
    Npm.Run(frontend, "build:staging");
}

if (deploy)
{
    var appName = production ? "my-api-prod" : "my-api-staging";
    var pagesProject = production ? "my-frontend-prod" : "my-frontend-staging";

    Azure.EnsureAuthenticated();
    Dotnet.Publish(api, o => o.Output(Root / "publish" / "api"));
    AppService.DeployZip(appName, Root / "publish" / "api");

    Cloudflare.EnsureAuthenticated();
    Cloudflare.PagesDeploy(frontend / "dist", pagesProject);
}

Usage:

# Deploy to staging
ando -p deploy

# Deploy to production
ando -p deploy,production

Full Example with Tests

Complete full-stack pipeline with testing:

var deploy = DefineProfile("deploy");

var api = Dotnet.Project("./src/Api/Api.csproj");
var apiTests = Dotnet.Project("./tests/Api.Tests/Api.Tests.csproj");
var frontend = Directory("./frontend");

// === Backend ===
Dotnet.SdkInstall();
Dotnet.Restore(api);
Dotnet.Build(api);
Dotnet.Test(apiTests);

Dotnet.Publish(api, o => o
    .WithConfiguration(Configuration.Release)
    .Output(Root / "publish" / "api"));

// === Frontend ===
Node.Install();
Npm.Ci(frontend);

// Run frontend tests
Npm.Test(frontend);

// Build for production
Npm.Build(frontend);

// === Deploy ===
if (deploy)
{
    // Database migrations
    Azure.EnsureAuthenticated();
    var dbContext = Ef.DbContextFrom(api, "AppDbContext");
    Ef.DatabaseUpdate(dbContext, Env("CONNECTION_STRING"));

    // Deploy API
    AppService.DeployWithSwap("my-api", Root / "publish" / "api", "staging");

    // Deploy frontend
    Cloudflare.EnsureAuthenticated();
    Cloudflare.PagesDeploy(frontend / "dist", "my-frontend");
    Cloudflare.PurgeCache("example.com");

    Log.Info("Full stack deployment complete!");
}

// Copy artifacts for local inspection
Ando.CopyArtifactsToHost("publish", "./dist");

Key Operations

OperationPurpose
Dotnet.Publish()Build .NET for deployment
Npm.Build()Build frontend assets
AppService.DeployZip()Deploy to Azure App Service
Cloudflare.PagesDeploy()Deploy to Cloudflare Pages

See Also