CI/CD Setup
Set up automated deployments using GitHub Actions.
Overview
The CI/CD pipeline automates your deployment workflow:
- Quality checks run on every pull request (build, lint, type-check, tests)
- Deployments are triggered manually per environment
Prerequisites
Set Your Cloud Provider
Before generating workflows, your project needs a cloud provider configured in .tsdevstack/config.json. There are two ways to do this:
Option 1: Via cloud:init (if you have local credentials set up)
This validates credentials, registers resource providers, and sets the provider in config.json.
Option 2: Manually (CI-only setup, no local credentials needed)
Edit .tsdevstack/config.json and set the cloud.provider field:
Valid values: "gcp", "aws", "azure".
Cloud Account Setup
Each provider requires a cloud account with the right permissions before CI can deploy. Follow your provider's account setup guide:
- Azure Account Setup — App Registration, Resource Group, Permissions
- GCP Account Setup — Project, Service Account
- AWS Account Setup — Account, IAM User
Generating Workflows
Initialize CI/CD
The command reads your cloud provider from config.json and prompts for target environments. You can also pass environments directly:
infra:init-ci and infra:generate-ci only need the cloud provider set in config.json. No local cloud credentials (.credentials.*.json) are required. This means you can generate CI workflows without running cloud:init.
This command:
- Creates
.tsdevstack/ci.jsonconfiguration - Generates workflow files in
.github/workflows/ - Generates
infrastructure.schema.jsonfor your provider - Prints setup instructions for your cloud provider
Configuration
The generated .tsdevstack/ci.json:
Regenerate After Changes
After modifying ci.json (e.g., adding environments):
Generated Workflows
Running Deployments
- Go to Actions in your GitHub repository
- Select the workflow (e.g., Deploy)
- Click Run workflow
- Select the target environment
- Fill in additional options (varies by workflow):
- Tag - image tag (defaults to commit SHA)
- Service checkboxes - select which services to deploy (deploy-services)
- Service name - name of service/worker to remove (remove workflows)
- Dry run - preview what would be deleted without deleting
- Click Run workflow
GitHub Secrets
Workflows need secrets to authenticate with your cloud provider. Add these as repository secrets in Settings > Secrets and variables > Actions.
Secrets are environment-prefixed: each secret name ends with the environment in uppercase (e.g., _DEV, _STAGING, _PROD). Workflows dynamically look up the right secret based on the selected environment.
For each environment, add the same set of secrets with the corresponding suffix (_STAGING, _PROD, etc.).
See the provider-specific setup guides for where to find these values:
- GCP CI/CD - Workload Identity Federation setup
- AWS CI/CD - IAM role setup
- Azure CI/CD - Federated credentials setup
Private npm packages
If your project depends on private npm packages (private GitHub Packages, private scoped packages on registry.npmjs.org, internal company registries), tsdevstack auto-wires NPM_TOKEN through both local docker builds and CI workflows.
Trigger: presence of an .npmrc file at the project root with ${NPM_TOKEN}-style env-var interpolation:
.npmrc — it has no secrets
The file contains no actual secret — ${NPM_TOKEN} is an env-var reference; npm interpolates from the environment at install time. Committing the template is the standard npm-ecosystem pattern, and required for CI (CI runners only see committed files).
If your .gitignore blanket-excludes **/.npmrc, add an exception so the project-root template is tracked:
The blanket-ignore is a defensive default that catches npm login-generated files containing real tokens. A hand-written template with ${NPM_TOKEN} interpolation is safe to commit.
Setup
-
Create
.npmrcat the project root and commit it. Add lines for any additional private registries you use. -
Locally — export
NPM_TOKENin your shell:Or persist it in
~/.zshrc/~/.bashrc.npx tsdevstack infra:build-dockerandinfra:deployautomatically forward it as a BuildKit env-source secret. -
In CI — add
NPM_TOKENas a single GitHub repository secret (Settings → Secrets and variables → Actions). Single value, not per-environment — registry tokens identify your developer / org account, not a deployment target. -
Regenerate workflows so the
NPM_TOKENenv block lands in the generated YAML:
How it threads through
Security properties
NPM_TOKENis mounted only during thenpm ciRUNstep — never persisted in image layers, never visible indocker history.- The
.npmrclives only in thedepsandbuildintermediate stages; theproductionstage starts fresh and does not COPY it across, so the final shipped image is clean. - The
.npmrccontent itself is just${NPM_TOKEN}template (no real secret), so even cache layers pushed to a registry leak nothing sensitive. - If
.npmrcis present butNPM_TOKENis unset, BuildKit fails fast with a clear error — misconfiguration is loud. - If
.npmrcis absent, generated workflows and Dockerfiles emit noNPM_TOKENwiring at all (behavior identical to public-only projects).
Verification
After regeneration, inspect any generated .github/workflows/*.yml — you should see the env: block at the job level (sibling of permissions: and steps:):
And in infrastructure/docker/<service>.Dockerfile:
User Secrets
Before the first deployment, you need to create user secrets in your cloud provider's secret manager. Each provider's CI/CD guide covers which secrets are required and how to create them:
Adding a New Environment
- Create the cloud project/account for the new environment
- Add credentials with
npx tsdevstack cloud:init - Update
.tsdevstack/ci.json: - Regenerate workflows:
npx tsdevstack infra:generate-ci - Add GitHub secrets for the new environment (provider-specific)
- Push secrets:
npx tsdevstack cloud-secrets:push --env staging - Deploy:
npx tsdevstack infra:deploy --env staging