Skip to content
Slicekit

Operations

Configuration

How the template is configured: appsettings as development placeholders, environment-variable overrides in production, and the local port map.

View .md
On this page

One rule: placeholders in, environment variables out

Configuration follows a single principle. The values committed to appsettings.json are development placeholders that let you clone and run the stack with docker compose up -d and no extra setup. Every secret or environment-specific value is overridden by an environment variable in any real environment.

There is no Key Vault or Secrets Manager scaffolding to adopt. Point your platform’s secret mechanism (Docker secrets, Kubernetes Secret, your host’s env panel) at environment variables and you are done. Nothing in the repo needs to change to deploy.

This page covers the API and SPA. The marketing site has its own customization guide: see customising the landing site.

The double-underscore convention

.NET maps environment variables onto the configuration tree by replacing each : with __ (two underscores). A nested key in appsettings.json becomes a flat environment variable:

{
  "ConnectionStrings": { "Postgres": "Host=localhost;..." },
  "Cors": { "AllowedOrigins": ["http://localhost:3003"] }
}
ConnectionStrings__Postgres="Host=db;Port=5432;Database=slicekit;Username=...;Password=..."
Cors__AllowedOrigins__0="https://app.example.com"

Array entries are addressed by index (__0, __1). This is the standard ASP.NET Core binding, so anything you can put in appsettings.json you can override from the environment without touching code. Strongly-typed settings are bound the same way, see the settings pattern.

Common overrides

The values you will set in production, grouped by concern:

ConcernVariables
DatabaseConnectionStrings__Postgres
Cache/sessionsConnectionStrings__Redis
MessagingRabbitMq__Host, RabbitMq__Username, RabbitMq__Password
File storageStorage__Endpoint, Storage__AccessKey, Storage__SecretKey, Storage__Bucket
CORSCors__AllowedOrigins__0, Cors__AllowedOrigins__1, …
OAuthAuthentication__Google__ClientId, Authentication__Google__ClientSecret
TelemetryOTEL_EXPORTER_OTLP_ENDPOINT (the OTLP collector your traces and audit log flow to)

Storage points at MinIO locally and any S3-compatible bucket in production (see file storage). OAuth client credentials are added per provider (see adding an OAuth provider). Telemetry exporters are plain OTLP, so they target your collector (see observability).

The local port map

docker compose up -d brings up the full local stack. The dev servers and infrastructure use a fixed set of ports:

ServicePortNotes
Frontend3003Vite dev server; matches Cors:AllowedOrigins
API5076 / 5077http / https from Kestrel
Postgres5432
Redis6379
RabbitMQ5672 / 15672broker / management UI
Mailpit1025 / 8025SMTP / web UI
MinIO9000 / 9001S3 API / console
Grafana3010dashboards
Prometheus9090
Loki3100logs and the audit trail
Tempo3200traces
Alertmanager9093

The frontend dev server on 3003 is the origin allowed by Cors:AllowedOrigins, so the SPA and API agree out of the box. If you change the frontend port, update that origin.

Production

In production you run the same images with environment variables supplied by your platform:

docker compose -f docker-compose.prod.yml up -d --build

Terminate TLS at your proxy or load balancer and forward the scheme and client address; the API trusts forwarded headers so cookies, redirects and audited IPs stay correct. See reverse proxy and deployment for the full topology.

Checklist

  • Treat appsettings.json as placeholders; never commit a real secret.
  • Override secrets and environment-specific values with environment variables, using __ for :.
  • Set Cors__AllowedOrigins to your real frontend origin(s).
  • Point OTEL_EXPORTER_OTLP_ENDPOINT and Storage__* at your infrastructure.
  • Run migrations as an explicit deploy step (see deployment).