---
title: Quickstart
description: Run your first Specdiff comparison and your first Envlock validation in under five minutes.
url: https://pr-1-ee19382a0710.thally.app/quickstart
---

# Quickstart

Run your first Specdiff comparison and your first Envlock validation in under five minutes.

## Specdiff -- detect breaking changes

Specdiff compares two JSON Schema or OpenAPI documents and reports every
breaking change. Install the CLI, point it at two files, and read the result.

### Install

```bash
npm install -D @specdiff/cli
```

### Compare two specs

```bash
npx specdiff before.yaml after.yaml
```

Specdiff auto-detects whether the files are OpenAPI or plain JSON Schema.

### Sample output

```text
Breaking (3):
  type-changed          #/properties/age/type             type changed from "integer" to "string"
  property-removed      #/properties/email                property removed
  required-added        #/properties/address/required      property "zip" added to required

Warning (1):
  format-changed        #/properties/created/format       format changed from "date" to "date-time"

Info (1):
  property-added        #/properties/nickname             property added

5 changes: 3 breaking, 1 warning, 1 info
```

The CLI exits with code 1 when breaking changes are found (configurable with
`--fail-on`), so you can wire it directly into a CI step.

### Next steps

See the [Specdiff overview](/specdiff/overview) for the full API, rule
catalogue, CI recipes, and MCP setup.

---

## Envlock -- validate environment variables

Envlock lets you declare a typed contract for every variable your app reads,
then validates the real environment against it.

### Install

```bash
npm install @envlock/core
```

### Define a contract

Create an `envlock.config.mjs` file at the root of your project:

```js
import { defineEnv, env } from "@envlock/core";

export default defineEnv({
  NODE_ENV: env
    .enum(["development", "test", "production"])
    .default("development"),
  PORT: env.port().default(3000).describe("HTTP listen port"),
  DATABASE_URL: env
    .url({ protocols: ["postgres:", "postgresql:"] })
    .secret()
    .describe("Primary database connection string"),
});
```

Each field carries its type, a default or required flag, an optional
description, and a secret marker that redacts the value in logs and error
messages.

### Load and validate at startup

```js
import { loadEnv } from "@envlock/core";
import schema from "./envlock.config.mjs";

const config = loadEnv(schema);
// config.PORT is a number, config.DATABASE_URL is a string, etc.
```

`loadEnv` reads `process.env`, parses every value according to the contract,
and either returns a fully typed object or throws an `EnvValidationError`
listing every issue at once.

### Check from the command line

Install the CLI and run `envlock check` to validate the current environment
against your contract without starting the app:

```bash
npm install -D @envlock/cli
npx envlock check
```

A passing run prints:

```text
ok: process.env satisfies 3 declared variable(s)
```

A failing run lists every issue:

```text
error: 1 issue in process.env

KEY           CODE     MESSAGE
DATABASE_URL  missing  required variable is not set
```

### Next steps

See the [Envlock overview](/envlock/overview) for the full builder reference,
CLI commands, dotenv support, and MCP setup.