v0.11.0
Released: October 28, 2026
This release is about secrets. Each service reads the shared secrets and its own, on every provider, and the cloud permissions follow the same rule. Azure gets a Key Vault per service, and the gateway reads its secrets when it starts. Existing environments upgrade with two new commands.
Secrets per service
- Each service reads two scopes: shared and its own.
- When a key is in both, the service's own value wins. This works the same locally and on every provider.
- Both scopes are read in parallel.
- A secret that doesn't exist is "not found". Access and network problems are reported as errors.
- One cache for every provider: 5 minutes in the cloud, 1 minute locally. URLs are never cached.
Auth secrets
- The JWT signing keys, the refresh token secret,
BCRYPT_ROUNDSandADMIN_EMAILSlive in the auth service's scope. Only the auth service reads them. cloud-secrets:pushkeeps an environment's existing keys, so your users stay logged in.cloud-secrets:set,getandremovefind these keys in the auth service's scope.- The gateway trust token and the service API keys are shared. Every service checks them.
Cloud permissions
- GCP and AWS: each service's account reads the shared secrets and its own. Names are matched exactly, so
authandauth-servicestay apart. - Azure: each backend service gets its own Key Vault next to the shared one. Its identity reads the shared vault and its own.
- AWS: the role that starts containers reads the shared secrets and each service's database URL. The database setup tasks have a role of their own.
- Reserved names:
shared,secretsandkvcan't be service names, and neither can names starting withshared-.
Gateway secrets at startup
The gateway image holds no secrets. Its config references them ({vault://env/redis-password}), and the gateway reads them from its environment when it starts.
- Locally: docker-compose passes them from the root
.env. - GCP: Cloud Run sets them from Secret Manager.
- AWS: the task definition injects them.
- Azure: App Service reads them from Key Vault.
infra:deploy-kongwaits until all three are resolved.
The gateway's identity reads exactly these three secrets. A new framework plugin, tsdevstack-trust, sets the trust header.
New commands
cloud-secrets:migratecopies secrets from where earlier versions kept them to where services read them now. It never deletes or overwrites.cloud-secrets:cleanupdeletes the old copies after the deploy. It asks first. A copy whose value differs from the new one gets its own question, and--forcenever deletes it. On Azure, it runs once every service is on the new deploy.cloud-secrets:set --stdinreads the value from standard input. It stays out of your shell history and the process list.
The MCP server (cli-mcp 0.9.0) has two new tools, cloud_secrets_migrate and cloud_secrets_cleanup, and an upgrade workflow in its guide.
Pushing your secrets
cloud-secrets:pushpushes the values in a service's section of.secrets.user.jsonto that service's scope.- Values in a frontend's or a worker's section are listed, not pushed.
- Values only local development needs stay local.
Improvements
- Login takes the same time whether or not the email has an account. Projects created before this version apply the change themselves: see the upgrade steps.
- nest-common declares
class-transformerandclass-validator, so every NestJS service image has them. cloud:initon Azure checks that it can read the Key Vault's secrets, and names the missing role when it can't.cloud-secrets:pushlists each secret that failed, with its error, and continues with the others.- Deploys tag images with the last commit. Without
--tag, they warn about uncommitted changes. - Azure: Key Vault names are the same in every command, for any project name length.
- Azure: the deploy stops with an error when it can't read the managed identities.
- GCP: the deploy lists only the DNS records that are missing, with what each one is for.
- GCP: when Google is still releasing the network, destroy says so and tells you to run it again later.
Breaking changes
Pre-1.0, so they ship in a minor version. The upgrade steps below cover each.
- nest-common:
SecretsService.set()anddelete()are removed. CustomSecretsProviderimplementations implementread(key, scope). - Lookup order: a service's own value wins over a shared one with the same key.
kong.user.yml: the Kong commands stop while arequest-transformeraddsX-Kong-Trust:${KONG_TRUST_TOKEN}.- Existing cloud environments run
cloud-secrets:migratebefore their first deploy with this version. - Reserved names: a service named
shared,secretsorkv, or starting withshared-, needs a new name. - AWS with the scoped IAM statements: add
arn:aws:iam::*:role/PROJECT_NAME-db-tasks-executiontoManageFrameworkRoles.
Upgrading an existing project
1. Packages.
Run the second command for each NestJS service. Remove any calls to SecretsService.set() or delete().
2. kong.user.yml. In the request-transformer plugin, delete X-Kong-Trust:${KONG_TRUST_TOKEN} from add.headers and X-Kong-Trust from remove.headers. If add is left empty, delete it too.
3. Auth service. If your auth service came from the template, add this to src/auth/auth.service.ts:
4. Local stack.
This moves the auth secrets into the auth service's section of .secrets.local.json. It also gives the gateway its three secrets from the root .env.
5. Each cloud environment. In this order:
migrate only copies, and cleanup only deletes the old copies. If your environments deploy from CI only, run these once from a machine with the environment's credentials.
New projects get all of this from the start.