---
title: "Know what normal looks like for your app"
description: "Turn on norms, read what the app has learned, and get an anomaly signal when traffic, errors or loop delay leave their usual range."
section: "guides"
status: "Building for 0.4"
spec: "norms"
canonical: "https://mainsdk.dev/docs/guides/use-norms"
updated: "2026-10-28"
---

# Know what normal looks like for your app

> Turn on norms, read what the app has learned, and get an anomaly signal when traffic, errors or loop delay leave their usual range.

Status: Building for 0.4 · Canonical: https://mainsdk.dev/docs/guides/use-norms · Updated: 2026-10-28

You will add `norms` to your app, read what it learned and play an afternoon of traffic against it in a test. It takes about 15 minutes.

## You need

- A MainSDK app with a `main.yaml` (see [Thirty-minute path](https://mainsdk.dev/docs/getting-started/thirty-minutes)).

## 1. Turn learning on

```yaml title="main.yaml"
norms:
  season: hour-of-week
  tz: Asia/Kolkata
  learn: 7d
```

Run `npx mainsdk check`. A wrong value is reported as `MAIN-NORMS-0001` with the key named.

## 2. Read what it learned

```ts
import { norms } from "mainsdk";

const view = await norms.get("requests");
console.log(view.bucket, view.n, view.p50, view.p99, view.learning);
const page = await norms.list();   // one view per metric
```

`learning` stays true until the model is `learn` old and a bucket has `min-samples` values.

## 3. Listen for anomalies

```ts
import { signals } from "mainsdk";

signals.on("anomaly.*", (s) => console.log(s.name, s.subject, s.data));
```

A metric must stay out of range for `hold` windows before one `anomaly.detected` is sent.

## 4. Test it with a simulated afternoon

```ts
import { createSim, sine } from "@mainsdk/testing";

const sim = createSim({ apps: { web: { main: "./main.yaml" } }, seed: 42 });
sim.inject.traffic("web", { rps: sine({ min: 1, max: 8, period: "24h" }) });
await sim.run("14d", { step: "1s" });
sim.expect.none("web", "anomaly.detected");
```

## 5. Forget a model after a migration

```ts
import { norms } from "mainsdk";

await norms.delete("requests", { reason: "migrated to a new checkout" });   // needs norms.manage
```

## Check it worked

Run `npx mainsdk norms`. It lists each metric with its bucket and count.
