Tech Stack

What metrd is built with.

metrd is a monorepo of three deployable pieces plus a shared package, built and released independently.

App

The user-facing web app.

  • Next.js 16 (App Router) with React 19
  • TypeScript, strict mode
  • SignalR (@microsoft/signalr) for the live connection that drives the display
  • Generated API client (packages/api-client), produced by parsing the API's C# controllers and SignalR hubs directly - no separate schema to keep in sync

API

The backend service.

  • ASP.NET Core on .NET 10
  • Entity Framework Core with Npgsql for PostgreSQL
  • Layered as ServiceBusinessData, with Client holding shared request/response contracts and Integration holding third-party integration clients, kept dependency-free from the rest of the API
  • Custom Roslyn analysers (Metrd.API.Analysers) enforce project-specific conventions at compile time, with code fixes provided where practical
  • MSTest and Moq for unit tests, plus dedicated convention tests that check structural and naming rules across every project

Site

This documentation and marketing site.

  • Next.js 16 with TypeScript
  • Docs are plain Markdown files under Site/docs/, rendered via next-mdx-remote, with the sidebar generated automatically from the folder structure

Infrastructure

  • PostgreSQL 17 as the primary database
  • Docker images for the API and App, published to GitHub Container Registry
  • GitHub Actions for PR checks, image publishing, and a Docker Compose smoke test on every change to the stack

Performance principles

metrd is built to run on light hardware, not a beefy server, so keeping the API and database frugal is a first-class concern rather than an afterthought:

  • Reference data that rarely changes (units, metrics, currencies, display layouts) is served from an in-process hybrid cache rather than re-queried on every request.
  • Readings are bucketed for retention (see Readings) so history doesn't grow without bound and older queries scan less data.
  • The layered architecture keeps data access confined to repositories, which makes it straightforward to see and control exactly where a database round trip happens.

The guiding rule: every request and every trip to the database counts, so avoid the ones you don't need.

See Coding Standards & Contributing for how these pieces fit together day to day.