OSS-first docs

These docs teach the open system first: contracts, generated surfaces, runtimes, governance, and incremental adoption. Studio shows up as the operating layer on top, not as the source of truth.

Next.js: add one endpoint

Add ContractSpec to an existing Next.js App Router project by wiring a single operation end-to-end with validation and types.

What you'll build

  • One OperationSpec with SchemaModel validation.
  • A registry wiring the operation to its handler.
  • A Next.js route handler that exposes the operation.

1) Install core packages

nextjs-install
bun add -D contractspec
bun add @contractspec/lib.contracts-spec @contractspec/lib.contracts-runtime-server-rest @contractspec/lib.schema

Expected output: added 3 packages and a lockfile update.

2) Define the operation spec

Create src/contracts/healthcheck.operation.ts:

src/contracts/healthcheck.operation.ts
import { defineQuery } from "@contractspec/lib.contracts-spec/operations";
import { SchemaModel, ScalarTypeEnum } from "@contractspec/lib.schema";

const HealthcheckOutput = new SchemaModel({
  name: "HealthcheckOutput",
  fields: {
    status: { type: ScalarTypeEnum.NonEmptyString(), isOptional: false },
    checkedAt: { type: ScalarTypeEnum.DateTime(), isOptional: false },
  },
});

export const HealthcheckQuery = defineQuery({
  meta: {
    key: "healthcheck.get",
    version: "1.0.0",
    description: "Return service health status",
    owners: ["@platform.core"],
    tags: ["health", "observability"],
  },
  io: {
    input: null,
    output: HealthcheckOutput,
  },
  policy: {
    auth: "public",
  },
  transport: {
    rest: { method: "GET" },
    gql: { field: "healthcheck_get" },
    mcp: { toolName: "healthcheck_get-v1" },
  },
});

3) Register the operation

Create src/contracts/registry.ts:

src/contracts/registry.ts
import {
  OperationSpecRegistry,
  installOp,
} from "@contractspec/lib.contracts-spec/operations";
import { HealthcheckQuery } from "./healthcheck.operation";

export const registry = new OperationSpecRegistry();

installOp(registry, HealthcheckQuery, async () => ({
  status: "ok",
  checkedAt: new Date().toISOString(),
}));

4) Add the Next.js handler

Create app/api/ops/[...route]/route.ts:

app/api/ops/[...route]/route.ts
import { makeNextAppHandler } from "@contractspec/lib.contracts-runtime-server-rest/rest-next-app";
import { registry } from "@/contracts/registry";

const handler = makeNextAppHandler(registry, async () => ({
  actor: "public",
  tenantId: "public",
}));

export { handler as GET, handler as POST };

Expected output: the route responds at /api/ops/healthcheck.get.

5) Validate the spec

nextjs-validate
contractspec validate src/contracts/healthcheck.operation.ts

Expected output: Validation passed.

Example package

Use @contractspec/example.lifecycle-dashboard as a lightweight Next.js snippet reference.

nextjs-example
# Inspect the example docs
contractspec examples show lifecycle-dashboard

# Validate all example manifests in this repo
contractspec examples validate --repo-root .

Want real product evidence behind endpoint changes?

Studio correlates meetings, support, analytics, and code signals before compiling endpoint decisions into spec diffs.

See what Studio adds
OSS docsbuildStart with OSS. Adopt Studio when you want the operating layer.

Why ContractSpec

Keep educational and comparison content reachable without letting it define the primary OSS learning path.