For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /docs/releases/v0.12.0.md.

v0.12.0

Released: November 6, 2026

This release is about seeing what your app does in the cloud. One command reads the logs of every part of an environment. Every request is one trace, from the Next.js frontend through Kong to each service and database query. Each environment gets a dashboard in its cloud's console. It all works the same on GCP, AWS and Azure, with no setup. The Terraform providers move to their latest majors, and background work starts the moment it's queued, on every cloud.


Cloud logs

infra:logs reads a deployed environment's logs from your terminal.

  • Every source: NestJS services, workers, Next.js apps, Kong, migration runs, scheduled jobs, and the load balancer and WAF in front of them.
  • The source list: without a source name, the command lists the sources and when each one last logged.
  • One timeline: --all merges every source. Each line is tagged app (your code), platform (deploys, starts, stops, crashes, health checks) or edge (requests and WAF blocks).
  • Filters: --since, --until, --level, --kind, --grep and --json. Times are UTC.
  • No line limit. Lines print as they arrive, and the filters narrow them down.
  • Log level per service: logLevel in infrastructure.json, default info. LOG_LEVEL in your secrets stays local.
npx tsdevstack infra:logs --env prod
npx tsdevstack infra:logs auth-service --env prod --since 2h --level error
npx tsdevstack infra:logs --all --env prod --grep <trace id>

Per provider:

  • GCP: Google allows 60 log reads per minute per project. When a read reaches that limit, the command keeps the lines it printed and gives you a Logs Explorer link with the same query. The deploy account gets the Logs Viewer role.
  • AWS: platform lines come from ECS service events and stopped tasks, with the reason and exit code. Each scheduled job run logs its start, status and duration. The WAF log leaves out the Authorization, Cookie and frontend token headers.
  • Azure: Container Apps log to resource-specific tables, and Kong and the Next.js apps add their App Service platform logs. Scheduled job runs log the response and its status.

The MCP server (cli-mcp 0.10.0) has a new tool, get_logs. It returns the newest 200 lines of the window and says what it left out, so an agent narrows the query instead of guessing. Logs can hold personal data, so the tool tells the agent to ask you before every read. get_secret does the same, and the secrets resources (tsdevstack://secrets/user, tsdevstack://secrets/names) show key names only. get_secret also reads a service's scope (service). See Cloud Logs.

Traces

Every request is one trace:

  • Next.js frontend: its server spans and its calls to Kong.
  • Kong: the request and the call to the service.
  • Services and workers: the request, calls to other services, BullMQ jobs and messages.
  • Database: each Prisma query, with the SQL and its $1 placeholders, never the values.

A queued job and a message handler run in the trace of the request that started them.

Traces go to each cloud's own service: Cloud Trace on GCP, X-Ray through CloudWatch Transaction Search on AWS, Application Insights on Azure. Locally they go to Jaeger. Each service signs in with its own cloud identity, so there are no keys or connection strings to manage. Kong sends its spans to a collector container that runs beside it and keeps its memory under 200 MiB.

  • Logs and traces together: every line a service logs inside a request carries trace_id. infra:logs --grep <trace id> finds the request's lines in every service. The GCP console links logs and traces both ways, and AWS lines carry xray_trace_id.
  • Sampling: tracing.sampleRate per environment, default 1 (every trace). Kong decides for each request, and the services follow.
  • Your trace IDs stay yours: Kong drops trace headers from outside clients and keeps the ones from your frontend. The frontend starts a new trace for each browser request.
  • Quiet probes: health checks and /metrics get no spans, in Kong and the Next.js apps too.

The new @tsdevstack/telemetry package does the export for nest-common and the Next.js frontends. See Traces and Dashboards.

AWS: Transaction Search is account-wide

infra:deploy turns on Transaction Search for the AWS account. It changes how X-Ray bills every app in the account, and it stays on after infra:destroy.

At high traffic, traces cost money, and on Azure from moderate traffic on. Set tracing.sampleRate to keep a share of them. The cost pages show the numbers for GCP, AWS and Azure.

Dashboards

Each environment gets a dashboard in its cloud's console: Cloud Monitoring on GCP, CloudWatch on AWS, an Azure Monitor workbook on Azure. infra:deploy creates it and prints its link. The panels cover the services, Kong and Next.js, the database, Redis, the edge and the error lines.

Each database records statistics per query:

  • GCP: Cloud SQL Query Insights.
  • AWS: Database Insights, with Performance Insights on for 7 days (free).
  • Azure: Query Store on General Purpose and Memory Optimized tiers, and the enhanced Postgres metrics on every tier. Microsoft advises against Query Store on Burstable tiers, so the workbook says why it's off there.

AWS: Container Insights is off. The dashboard uses the free ECS metrics, and crashes and restarts show in infra:logs. By AWS's pricing example, that saves a small environment about $46-49 a month.

Background work

Queue processors and message handlers run in workers, which always run. Work starts the moment it's queued, on every cloud.

  • Workers scale on CPU between minInstances and maxInstances: at 70% on AWS and Azure, at Cloud Run's 60% on GCP.
  • The auth template comes with auth-worker, which sends the emails.
  • npm run dev starts the workers next to the services, with their output in the same terminal.
  • GCP: NestJS services with minInstances 1 or more run with CPU always on, so their own background work runs between requests too. At the default size (1 vCPU, 512 MiB) that is about $50 a month per service instead of about $10. Set minInstances: 0 to keep request-based billing and scale to zero.
  • Azure: services run one instance by default (minInstances 1). Set 0 to scale to zero.

Messaging:

  • A handler that runs long keeps its messages, so another instance doesn't run them a second time.
  • A stream keeps each message until every subscriber group has handled it.
  • A service deletes its consumer group on a topic it doesn't subscribe to anymore, about 15 minutes after the deploy.

Terraform providers

  • AWS 6, Google 8 and azurerm 5. Azure adds the azapi provider for the traces rule.
  • Provider upgrades are explicit. infra:plan and infra:deploy stop when the lock file is older than the new versions, and name the command to run: infra:plan --upgrade. You review the plan and commit the lock file, and CI uses it.
  • AWS: the scheduled job function runs on Node.js 24.
  • GCP: the load balancer stays the Classic Application Load Balancer.

Local development

  • Jaeger 2, Grafana 13 and Prometheus 3.
  • Kong sends its spans to Jaeger too, so a request is one trace locally, Kong included.
  • The Grafana dashboard sits in a tsdevstack folder that you can view without logging in.

Improvements

  • Azure: PostgreSQL accepts the current generation: GP_Standard_D2ds_v5, GP_Standard_D4ds_v5 and MO_Standard_E4ds_v5. Microsoft grants region access per size series, so a new subscription may get one generation and not the other. Azure account setup shows how to ask for it.
  • Azure: Front Door checks the Next.js apps on /health, the same path App Service checks.
  • AWS: Kong's task has 1 GiB by default, room for Kong and its collector. That is about $1.60 a month more per task.
  • AWS: migration logs are kept 30 days, like the service logs. Groups from earlier versions pick this up on their next migration.
  • infra:deploy ends with the dashboard link and, on Azure, the name servers of the DNS zone.
  • Next.js frontends log a failed API call in one line: method, path, status and message. Request bodies and headers stay out of the logs.
  • Email links (confirm email, reset password) carry the token after #. Browsers never send that part to a server, so the token stays out of every log, from the load balancer to Kong. Links already sent keep working.
  • Log redaction covers more names by default: accessToken, refreshToken, newPassword, currentPassword, passwordHash, privateKey, and the request headers that carry credentials (authorization, cookie, x-api-key and the framework's own). The observability page lists them and how deep they match.
  • Workers log and trace under their own name (auth-worker).
  • nest-common: ObservabilityModule.forRoot() works like the plain import, with one request line and one metric per request, and its logging, metrics and health options turn each part off.
  • Agent skills cover workers, messaging, traces, safe error logging in the frontend, and the Azure PostgreSQL sizes.
  • @tsdevstack/react-bot-detection: phone and pen users count as real pointer activity, and pasting or autofilling a one-field form (forgot password) goes through.
  • Dependencies: follow-redirects 1.16.2, and @azure/identity 4.14.1 with msal-node 7. npm audit shows no high or critical findings.

Breaking changes

Pre-1.0, so they ship in a minor version. The upgrade steps below cover each.

  • Terraform lock file: existing environments run infra:plan --upgrade once.
  • nest-common: TracingInterceptor is removed. createApp adds the request span as middleware.
  • kong.user.yml: a plugin named opentelemetry clashes with the framework's.
  • Queue processors run in workers only.
  • Messaging: maxLen caps a topic only while it has no subscriber, and the dead-letter stream. Before you remove a service that subscribes to topics, remove its subscriptions and deploy it.
  • GCP: NestJS services with minInstances 1 or more bill per instance, and a cpu below 1 fails validation for them (Google's rule for always-on CPU).
  • Azure: services default to minInstances 1, and Next.js apps answer /health with 200.
  • Permissions: GCP projects rerun infra:bootstrap. The Azure deploy service principal assigns Monitoring Metrics Publisher. The AWS CI role's policy includes xray:*.
  • @tsdevstack/react-bot-detection: handleFormSubmit and analyzeBehavior take { fieldCount }. The mouse-pattern rule is gone, and the reason "No natural mouse movement detected" reads "No natural pointer activity detected".

Upgrading an existing project

1. Packages.

npm install -D @tsdevstack/cli@^0.12.0
npm install @tsdevstack/nest-common@^0.12.0 -w <service>
npm update follow-redirects @azure/identity

Run the second command for each NestJS service. If your code uses TracingInterceptor, delete it: the request span is already there.

2. Workers. Move queue processors out of AppModule into a worker. For an auth service from the template, copy src/worker.ts, src/worker.module.ts and tsconfig.worker.json from the template, delete src/processors/processors.module.ts and its import in AppModule, and add the scripts to the service's package.json:

"start-worker:dev": "nest start --entryFile worker --watch --path tsconfig.worker.json",
"start-worker": "node dist/worker.js"

Then register the worker:

npx tsdevstack register-detached-worker --name auth-worker --base-service auth-service

In the root package.json, change dev so it starts the workers too:

"dev": "npm run clean:tsbuildinfo && npm run build:libs && NX_STREAM_OUTPUT=true lerna run dev,start-worker:dev --parallel"

3. Next.js frontends. For a frontend from the template:

npm install @tsdevstack/telemetry -w <frontend>

Add instrumentation.ts next to package.json:

import packageJson from "./package.json";

export async function register(): Promise<void> {
  if (process.env.NEXT_RUNTIME === "nodejs") {
    const { registerTelemetry } = await import("@tsdevstack/telemetry");
    registerTelemetry({
      serviceName: packageJson.name,
      serviceVersion: packageJson.version,
      continueIncomingTraces: false,
    });
  }
}

Add the trace interceptor to each Kong client, after forwardClientIp:

import { injectTraceContext } from "@tsdevstack/telemetry";

authClient.instance.interceptors.request.use(injectTraceContext);

Copy lib/utils/describe-error.ts and lib/utils/forward-client-ip.ts from the template. Log describeError(error) instead of the error object in handleApiError and in the console.error calls under app/api.

For the email links, copy lib/utils/take-link-token.ts, app/(public)/confirm/confirm-client.tsx and app/(public)/reset-password/reset-password-client.tsx from the template. The pages read the token after # and from ?token=. Then, in an auth service from the template, change the three links in src/auth/auth.service.ts to /confirm#token= and /reset-password#token=. Ship the frontend first, or both in the same deploy.

On Azure, a Next.js app answers /health with 200. The template has the route (app/health/route.ts).

4. kong.user.yml. If it has a plugin named opentelemetry, delete it. Kong's tracing comes from the framework.

5. Local stack.

npx tsdevstack sync

This moves the local stack to Jaeger 2, Grafana 13 and Prometheus 3 and turns on Kong's spans. To view the Grafana dashboard without logging in, delete ./data/grafana once.

6. Cloud accounts.

  • GCP: run npx tsdevstack infra:bootstrap --env <env>. It adds the Logs Viewer and Monitoring Dashboard Editor roles and turns on the trace, logging and monitoring APIs.
  • AWS: if you deploy from CI, add xray:* to the CloudWatchLogsAndMetrics statement of the role's policy. See AWS CI/CD setup.
  • Azure: add Monitoring Metrics Publisher to the roles the deploy service principal may assign (resource group > Access control > Role assignments > View/Edit in the Condition column). See Azure account setup.

7. Each cloud environment. First run a clean infra:plan with your current CLI version. Then:

npx tsdevstack infra:plan --env <env> --upgrade
npx tsdevstack infra:deploy --env <env>

Review the plan, then commit the updated .terraform.lock.hcl before you deploy. On Azure, Kong's App Service moves to two containers (Kong and its collector) with this deploy, and infra:logs reads the lines written after it.

New projects get all of this from the start.