Yes, Nx affected can be used to deploy only changed services to Cloud Run when combined with Workload Identity Federation. You compute the affected projects with Nx, filter the list to those that have a Docker image or service definition, and then run gcloud run deploy for each, using the federated identity for authentication. This approach avoids rebuilding and redeploying unchanged services, saving time and reducing the risk of introducing regressions.
Background: Nx Affected and Monorepo Deployments
Nx is a build system with smart rebuilds and caching. Its affected command analyzes the Git history and project graph to determine which projects are impacted by a change. In a monorepo with multiple deployable services, you want to deploy only the services that actually changed. The nx affected command is the standard way to get that list. However, the command alone does not know about Cloud Run or Docker; it simply outputs project names. You then need to map those projects to Cloud Run services and deploy them.
How Workload Identity Federation Fits In
Workload Identity Federation lets a CI/CD pipeline (like GitHub Actions, GitLab CI, or Cloud Build) authenticate to Google Cloud without a long-lived service account key. Instead, you create a workload identity pool and provider, then grant the pool’s principal access to a service account. When the pipeline runs, it exchanges a token from the CI provider for a Google Cloud access token. This is more secure than storing a JSON key and is the recommended way to authenticate automated deployments. For Cloud Run, you need the roles/run.admin role on the service account to deploy and the roles/iam.serviceAccountUser role to act as the runtime service account.
Step-by-Step: Deploying Only Changed Services
Here is a practical workflow for a GitHub Actions pipeline (the steps are similar for other CI systems):
- Checkout the code and set up Nx. Use the
actions/checkoutaction withfetch-depth: 0to get the full Git history, then install Node.js and Nx. - Authenticate with Google Cloud. Use the
google-github-actions/authaction with your workload identity provider and service account. This sets up the federated authentication. - Determine affected projects. Run
npx nx affected --target=build --base=origin/main~1 --head=origin/main(or use--base=origin/mainfor a merge-based comparison). This will build only the projects that changed. To just get the list, use--dry-runor--print-affected. - Filter to deployable services. The affected list may include libraries or non-deployable apps. You need a way to know which projects are Cloud Run services. A common approach is to use a tag in
nx.jsonorproject.json, like"tags": ["deploy:cloud-run"]. Then usenx affected --target=deploywith a customdeploytarget that runsgcloud run deploy. - Deploy each service. For each affected project, run the deploy command. In Nx, you can define a
deploytarget in the project’sproject.jsonthat callsgcloud run deploywith the right image name and service name. Using Nx’srun-manywith--target=deployand--projects=affectedwill do this in parallel.
Example deploy target in project.json for a service named api:
"deploy": {
"executor": "nx:run-commands",
"options": {
"command": "gcloud run deploy api --image us-docker.pkg.dev/my-project/my-repo/api:latest --region us-central1"
}
}
Then your CI would run npx nx affected --target=deploy --base=origin/main~1.
Common Problems and How to Avoid Them
- Affected list includes too many projects. If you use a wide base (like
origin/main), you may deploy more than needed. Use--base=origin/main~1for the last commit or--base=origin/mainfor a pull request merge. For pushes to main, you want the diff between the previous commit and the new one. - Projects that depend on changed libraries. Nx’s affected includes projects that depend on changed projects. That is usually correct: if a shared library changes, all services using it should be redeployed. If you don’t want that, you can filter the list manually, but that is risky.
- Authentication fails. Ensure the workload identity provider is correctly set up and the CI provider’s token is being exchanged. For GitHub Actions, the
google-github-actions/authaction handles this. For other CI, you may need to use thegoogle-auth-librarywith a custom script. - Deploying to the wrong region or project. Always set the
--projectand--regionflags in the deploy command, or set them via environment variables. - Image not built. If you deploy without building the image first, Cloud Run will fail. Make sure your build step runs before the deploy step, and that the image tag is unique per commit (e.g., using the commit SHA).
Comparing with Other Approaches
There are several ways to deploy only changed services to Cloud Run:
- Using
gcloud run deploywith a simple script. You can write a bash script that lists changed files and maps them to services. This is less maintainable than using Nx’s project graph, especially as the monorepo grows. - Using Cloud Build with Nx. Cloud Build can trigger on changes to specific directories, but that is not as precise as Nx’s dependency analysis. Nx will catch changes in shared libraries that affect a service, while a path-based trigger might miss them.
- Deploying everything. For small projects, it is simpler to deploy all services on every push. But as the number of services grows, this wastes time and resources.
- Using a dedicated deployment tool like Skaffold. Skaffold can handle monorepos, but it requires more configuration and does not integrate with Nx’s caching.
Nx’s approach is best when you have a large monorepo with many services and you want to leverage the project graph to avoid unnecessary builds and deployments.
Costs and Efficiency Considerations
The main cost saving is in CI time and compute. By deploying only changed services, you reduce the number of Docker builds and gcloud run deploy calls. Cloud Run itself charges per request and for instance time, so deploying unchanged services does not directly cost more (unless you keep old revisions). However, building and pushing images to Artifact Registry costs money and time. Nx’s caching can also skip builds if the source code has not changed, but the deploy step itself is not cached (it is a side-effect). So the efficiency gain is primarily in avoiding unnecessary builds and deployments.
Workload Identity Federation itself is free; you only pay for the underlying Google Cloud services. The main benefit is security: no long-lived keys to rotate or leak.
Frequently Asked Questions
Do I need to use Nx Cloud for this to work?
No. Nx Cloud is optional and provides remote caching and distributed task execution. The affected command works locally and in any CI. You can use Nx without Nx Cloud.
Can I use this with GitLab CI or other CI systems?
Yes. The same principles apply. You need to set up Workload Identity Federation for your CI provider. GitLab supports OIDC, and you can use the google-github-actions/auth action only for GitHub. For GitLab, you can use the google-github-actions/auth with a custom OIDC token, or use the google-auth-library in a script. The Nx affected command is CI-agnostic.
What if my service is not a Node.js app?
Nx can manage projects in multiple languages, including Go, Python, and Java. The deploy target can run any command, so you can use gcloud run deploy with any runtime. The key is that the project is defined in Nx with a project.json and has a deploy target.
How do I handle database migrations or other side-effects?
Deploying a service is a side-effect. If you have migrations, you should run them separately and only once. You can create a separate Nx target for migrations and run it only when the relevant project is affected. For example, nx affected --target=migrate.
What if I want to deploy to multiple regions?
You can define multiple deploy targets, e.g., deploy:us and deploy:eu, each with a different region. Then you can run nx affected --target=deploy:us and --target=deploy:eu separately. Or you can use a loop in the deploy command to iterate over regions.
Is it safe to use --base=origin/main~1 for every push?
Yes, if you always push to main and your CI runs on each push. But if you push multiple commits at once, origin/main~1 will only compare the last commit, missing changes from earlier commits. Better to use --base=origin/main~1 only if you force a single commit per push, or use --base=origin/main and rely on Nx’s merge-based detection. For pull requests, use --base=origin/main.
Related
Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.
More cards in this drawer
- O2 PUK Code and PIN Code Explained
- How to Host a Space Engineers Server
- Schedule Ride in Advance Uber: How It Works
- Optimize WordPress Themes for Mobile Performance
- Can AI Assistants Access Your Carrier Account?5.00 min/km
- How to Uninstall Docker Desktop on Mac