---
title: 'Service Defaults'
excerpt: 'OpenTelemetry, health checks, service discovery, and resilience wired through Aspire.ServiceDefaults.'
icon: 'Settings'
badge: 'New'
---

## What ServiceDefaults adds

Every Aspire service project references `Aspire.ServiceDefaults`. It centralizes observability, health endpoints, and HTTP resilience so individual APIs stay thin.

```csharp title="ServiceDefaults/Extensions.cs"
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Logging;
using OpenTelemetry;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;

namespace Microsoft.Extensions.Hosting;

public static class Extensions
{
    public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
    {
        builder.ConfigureOpenTelemetry();
        builder.AddDefaultHealthChecks();
        builder.Services.AddServiceDiscovery();
        builder.Services.ConfigureHttpClientDefaults(http =>
        {
            http.AddStandardResilienceHandler();
            http.AddServiceDiscovery();
        });
        return builder;
    }

    public static WebApplication MapDefaultEndpoints(this WebApplication app)
    {
        if (app.Environment.IsDevelopment())
        {
            app.MapHealthChecks("/health");
            app.MapHealthChecks("/alive", new HealthCheckOptions
            {
                Predicate = r => r.Tags.Contains("live")
            });
        }
        return app;
    }
}
```

## Wiring a consuming API

<DocsFileTabs title="Catalog API project files">

```csharp title="CatalogApi/Program.cs"
using CatalogApi.Data;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

builder.AddServiceDefaults();
builder.AddNpgsqlDbContext<CatalogContext>("catalog");

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

app.MapDefaultEndpoints();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

var products = app.MapGroup("/products");

products.MapGet("/", async (CatalogContext db) =>
    await db.Products.AsNoTracking().Take(50).ToListAsync());

products.MapGet("/{id:int}", async (int id, CatalogContext db) =>
    await db.Products.FindAsync(id) is { } product
        ? Results.Ok(product)
        : Results.NotFound());

products.MapPost("/", async (Product product, CatalogContext db) =>
{
    db.Products.Add(product);
    await db.SaveChangesAsync();
    return Results.Created($"/products/{product.Id}", product);
});

app.Run();
```

```csharp title="CatalogApi/Data/CatalogContext.cs"
using Microsoft.EntityFrameworkCore;

namespace CatalogApi.Data;

public sealed class CatalogContext(DbContextOptions<CatalogContext> options) : DbContext(options)
{
    public DbSet<Product> Products => Set<Product>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>(entity =>
        {
            entity.HasKey(p => p.Id);
            entity.Property(p => p.Name).HasMaxLength(200).IsRequired();
            entity.Property(p => p.Price).HasPrecision(18, 2);
            entity.HasIndex(p => p.Sku).IsUnique();
        });
    }
}

public sealed record Product(int Id, string Name, string Sku, decimal Price);
```

```json title="CatalogApi/appsettings.Development.json"
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.EntityFrameworkCore.Database.Command": "Information"
    }
  },
  "OpenTelemetry": {
    "Exporter": {
      "Otlp": {
        "Endpoint": "http://localhost:4317"
      }
    }
  }
}
```

</DocsFileTabs>

## Full AppHost bootstrap (long sample)

This sample is intentionally long — the docs code block collapses with **Expand** so pages stay scannable.

```csharp title="AppHost/Program.cs"
var builder = DistributedApplication.CreateBuilder(args);

var postgres = builder.AddPostgres("postgres")
    .WithPgAdmin()
    .AddDatabase("catalog");

var redis = builder.AddRedis("cache")
    .WithRedisCommander();

var rabbit = builder.AddRabbitMQ("messaging")
    .WithManagementPlugin();

var catalogApi = builder.AddProject<Projects.CatalogApi>("catalog-api")
    .WithReference(postgres)
    .WithReference(redis)
    .WithReference(rabbit)
    .WithHttpHealthCheck("/health");

var storefront = builder.AddProject<Projects.Storefront>("storefront")
    .WithReference(catalogApi)
    .WithExternalHttpEndpoints();

var worker = builder.AddProject<Projects.OrderProcessor>("order-processor")
    .WithReference(rabbit)
    .WithReference(postgres)
    .WithReplicas(2);

builder.AddProject<Projects.AdminPortal>("admin")
    .WithReference(catalogApi)
    .WithReference(storefront)
    .WithEnvironment("ASPNETCORE_ENVIRONMENT", "Development");

builder.AddAzureProvisioning();

var app = builder.Build();

app.Run();
```

## Install workflow

<InstallTabs>
  <InstallTab value="cli" label="CLI">
    <CommandBlock
      pnpm="dotnet add CatalogApi/Aspire.ServiceDefaults"
      npm="dotnet add CatalogApi/Aspire.ServiceDefaults"
      yarn="dotnet add CatalogApi/Aspire.ServiceDefaults"
      bun="dotnet add CatalogApi/Aspire.ServiceDefaults"
    />
  </InstallTab>
  <InstallTab value="manual" label="Manual">
    <Steps>
      <Step>Add the shared project reference</Step>

      ```xml title="CatalogApi/CatalogApi.csproj"
      <ItemGroup>
        <ProjectReference Include="..\ServiceDefaults\ServiceDefaults.csproj" />
      </ItemGroup>
      ```

      <Step>Call the extension methods in Program.cs</Step>

      ```csharp title="CatalogApi/Program.cs"
      var builder = WebApplication.CreateBuilder(args);
      builder.AddServiceDefaults();

      var app = builder.Build();
      app.MapDefaultEndpoints();
      app.Run();
      ```
    </Steps>
  </InstallTab>
</InstallTabs>

Next: configure **telemetry export** in the Monitoring chapter.
