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.9.0.md.

v0.9.0

Released: October 24, 2026

Three things stand out: RustFS replaces MinIO as the local S3 server (MinIO's images were removed from Docker Hub), rate limiting uses provider-specific client address headers and per-route limits, and Kong and Next.js scale on Azure App Service. Also in this release: IPv6 on every provider, deploys that wait out capacity shortages, database readiness at startup, cleaner logs.


Local development

  • RustFS replaces MinIO as the local S3 server. Same endpoint (http://localhost:9000) and console (9001); credentials rustfsadmin / rustfsadmin; data in ./data/rustfs/.

Rate limiting

  • Client address from the edge: X-Azure-SocketIP on Azure, X-Tsdevstack-Edge-IP on GCP and AWS. Clients cannot forge it.
  • Per-visitor limits behind the Next.js frontend: the new tsdevstack-client-ip gateway plugin and the KONG_FRONTEND_TOKEN secret.
  • Private path from the frontend to the gateway: a private endpoint on Azure (about $8 a month), Cloud Map on AWS.
  • Per-route limits in nest-common, with fixed windows.

Details in Client addresses and Rate limiting.

Azure

  • App Service scaling: minInstances and maxInstances set the instance count on Basic plans and a CPU autoscale range on Standard and Premium. See Azure App Service plans.
  • Managed Redis is private to your VNet.
  • infra:destroy removes the Container Apps and migration jobs too.
  • IPv6 on the apex domain; database.ha adds a zone-redundant standby; cloud:init checks the 12 resource providers.

GCP

  • IPv6 on the load balancer; the deploy prints the AAAA records. See GCP DNS & Domains.
  • Startup probe every 2 seconds; presigned URLs signed with each service's own identity.
  • Cloud Run resource rules are validated before a deploy; infra:bootstrap enables only the APIs in use.

AWS

  • IPv6 on every CloudFront distribution, with AAAA records in Route 53.
  • infra:destroy tears down the environment in one run.
  • database.diskSize, ha and backup apply; workers are pinned to the deployed image tag.

Every provider

  • Capacity retry: infra:deploy waits 5 minutes and tries again, up to 3 times.
  • infrastructure.json is validated in build and deploy commands.
  • Database readiness: waitForDatabase holds startup until the database answers; the pool keeps connections longer.
  • Redis certificate verification on AWS and Azure; /health includes Redis.

Cleaner logs

  • One entry per request with http.* fields; 4xx at warn, 5xx at error; probes at debug; Nest's own messages through the same logger.

Smaller improvements

  • Generated clients validate arrays, enums and maps as declared. Signup lowercases emails; login matches any case. API_KEY resolves through SecretsService everywhere. Secret prompts are masked. The local gateway image is named after your project. MCP tools fail fast on prompts and get 90 minutes for deploys.

Breaking changes

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

  • Secrets: run cloud-secrets:push once per cloud environment to create KONG_FRONTEND_TOKEN; infra:build-kong stops without it.
  • Gateway: a full kong.custom.yml must declare tsdevstack-client-ip itself. The deploy sets KONG_TRUSTED_IPS, KONG_REAL_IP_HEADER and KONG_REAL_IP_RECURSIVE.
  • AWS: KONG_INTERNAL_URL becomes http://kong.{project}.local:8080; the next deploy adds Cloud Map, a CloudFront function and AAAA records.
  • Local stack: storage credentials change to rustfsadmin; sync regenerates .env and docker-compose.yml. Files in ./data/minio/ are not carried over.
  • Rate limits: new counter keys (limits start from zero); routes count separately unless they share a customKeyGenerator key.
  • Settings that take effect on the next deploy: AWS database.diskSize (grows storage, cannot shrink), ha (Multi-AZ, about twice the cost), backup: false (retention 0); Azure database.ha (standby, about twice the cost), App Service instance counts (each billed), Kong's private endpoint with Next.js apps (about $8 a month).
  • Validation: values that deployed before can now fail: a tier from another provider, an Azure diskSize outside 32/64/128/256/512, redis.memoryGb outside GCP, cpu or memory on Kong or Next.js on Azure, ha on a Burstable tier, ha with backup: false on GCP, Cloud Run CPU below 1 without concurrency: 1.
  • Logs: request fields moved under http; the Incoming request entry is gone. cloud-secrets:push sends LOG_LEVEL=info.
  • nest-common: SecretsService.getProvider().getAll() is removed; /health reports Redis down (status degraded, still 200).
  • Generated clients: regenerated DTOs accept arrays and number | string fields as declared.
  • GCP: the first deploy with buckets moves the presigned URL permission; presigned URLs can fail for a few minutes.

nest-common 0.9.0

New: waitForDatabase. Changed: per-route rate-limit keys, request log format, Nest's logger routed through the framework logger, client address from X-Tsdevstack-Real-IP. Removed: getAll() on the secrets provider.

Upgrading an existing project

1. Update the packages.

npm install -D @tsdevstack/cli@^0.9.0
npm install @tsdevstack/nest-common@^0.9.0 -w auth-service   # repeat for each NestJS service

2. Refresh secrets and the local stack. npx tsdevstack sync locally (adds KONG_FRONTEND_TOKEN, switches to RustFS), then per cloud environment:

npx tsdevstack cloud-secrets:push --env <env>

3. Frontend: pass the visitor. Copy lib/utils/forward-client-ip.ts from a fresh npx @tsdevstack/cli init project and register it on every client your server uses to call the gateway (the template does it in lib/externalApi/auth-service.api.ts):

import { forwardClientIp } from "@/lib/utils/forward-client-ip";

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

4. Services: wait for the database. In each src/prisma/prisma.service.ts:

import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
import { createPrismaConnection, waitForDatabase } from '@tsdevstack/nest-common';
// other imports unchanged

@Injectable()
export class PrismaService
  extends PrismaClient
  implements OnModuleInit, OnModuleDestroy
{
  // pool, constructor and onModuleDestroy unchanged

  async onModuleInit(): Promise<void> {
    await waitForDatabase(this.pool);
  }
}

Optional, auth template: copy src/auth/normalize-email.ts and the auth.service.ts changes for lowercase emails.

5. Check infrastructure.json: npx tsdevstack infra:plan --env <env> validates it and shows what changes. Read "Settings that take effect on the next deploy" first.

6. Full kong.custom.yml only: add the global plugin (Kong Customization):

plugins:
  - name: tsdevstack-client-ip
    config:
      frontend_token: ${KONG_FRONTEND_TOKEN}
      client_ip_header: X-Tsdevstack-Client-IP
      token_header: X-Tsdevstack-Frontend-Token
      real_ip_header: X-Tsdevstack-Real-IP

7. Deploy: npx tsdevstack infra:deploy --env <env>. On GCP, add the printed AAAA records at your registrar. Point log-based alerts at the http.* fields.

8. Clean up (optional): docker image rm tsdevstack-kong:latest if your project has another name; on GCP, disable the Cloud Functions, Cloud Build and Serverless VPC Access APIs.

New projects get all of this from the templates.