---
title: "Working with NX, Railway and CI/CD"
description: "A brief guide on managing CI/CD for your NX projects using GitHub Actions with Railway."
date: 2022-09-16T00:00:00.000Z
updated: 2026-10-29T11:13:25.080Z
topics: ["Guides"]
tags: []
url: https://railway.com/guides/nx-railway-with-gh-actions
---

# Working with NX, Railway and CI/CD

Railway has first-party support for [NX monorepos](https://nx.dev/) through [Nixpacks](https://nixpacks.com/docs/getting-started), users may instead want to opt for [GitHub Actions](https://github.com/features/actions) in order to only create deployments for the affected services whenever they push a change.

In this article we will walk you through deploying a sample project on Railway to achieve that exact workflow.

## Setting up our sample project

We will use the [npm-libs](https://github.com/IgnisDa/npm-libs) repository by community member: [IgnisDa](https://ignisda.tech/) as our sample project. Within this repository, we will deploy the [remix-pagination-demo](https://github.com/IgnisDa/npm-libs/tree/main/apps/remix-pagination-demo) project.

You can start by forking that repository and deploying it within a project on Railway. Once you add the repository, go to the `variables` section and set the `NIXPACKS_NX_APP_NAME` variable to  `remix-pagination-demo`.

![Configuring the NX app name](https://cms.railway.com/media/bf7bc493d9a01bb25ff2e9a2658540b2ce68a58d14ae8d35d0e6963a8562e171.png)

Next, we can head over to the service settings and disable the GitHub trigger as we will be using GitHub actions to automatically trigger deployments for our project.

![Disabling the GitHub trigger on Railway](https://cms.railway.com/media/092781f0d4dae61b4417a9fb09e2d1021cc3fa24c17e5f5975a338b5cd0a2b74.png)

Next, create two separate [environments](https://docs.railway.com/environments). One for our `main` branch and one for the `dev` branch and head over to the project settings to create a [project token](https://docs.railway.com/integrations/api) for each environment.

![Creating project tokens](https://cms.railway.com/media/e319ab00db5c573c7cacef9578f19544a152d8c35bcd9a430aec2b0ccf78ab2b.png)

## Setting up our GitHub repository

Copy the project tokens from Railway and add them as [repository secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets) on GitHub. They should have the following naming scheme:

```
RAILWAY_TOKEN__<project_name>_<railway_environment>
```

![Repository secrets on GitHub](https://cms.railway.com/media/a8fb2037a2a5d3609f7cc8c60ea3ea4e4a5b8c3ec7d3aedae901276c0446d382.png)

## The GitHub action

Now, we need to set-up the workflow within GitHub to trigger a new deploy. 

The GitHub action workflow will:

- Run on every commit to the `main` and `dev` branches
- Test if a particular project has been affected
- If it has, deploy it to the correct environment on Railway

```yaml
name: Deploy affected projects

on:
  push:
    branches:
      - main
      - dev

env:
  NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - uses: ./.github/actions/setup
        name: Setup environment

      - name: Set base commit hash
        run: |
          #!/usr/bin/env bash
          commit=${{ github.event.before }}
          if git branch --contains "$commit"; then
            echo "No force push detected, continuing..."
          else
            # get the commit before this one
            commit=$(git log --format="%H" -n 2 | tail -n 1)
          fi
          echo "BASE_COMMIT=$commit" >> $GITHUB_ENV

      - name: Display base commit
        run: echo "$BASE_COMMIT"

      - name: Lint affected
        run: pnpm nx affected --target=lint --parallel=6 --base=$BASE_COMMIT --head=HEAD

      - name: Build affected
        run: pnpm nx affected --target=build --parallel=6 --base=$BASE_COMMIT --head=HEAD

      - name: Dump access secrets into file
        run: |
          mkdir -p ./dist
          echo '${{ toJSON(secrets) }}' >> ./dist/secrets.json

      - name: Deploy affected
        run: ./deployment/railway-trigger.sh
```

The main steps to note here are the:

- `Dump access secrets to file` step which converts the secrets into json format and dumps them into a file. This can be a potentially exploitable step if used in public repositories, so please make sure you take the appropriate cautions.
- `Deploy affected` step which triggers the [`railway-trigger.sh`](http://railway-trigger.sh/) script shared below.
    
    ```bash
    #!/usr/bin/env bash
    
    set -euo pipefail
    
    RAILWAY_BINARY="/tmp/railway"
    RAILWAY_VERSION="1.8.4"
    
    # Install the Railway CLI
    VERSION="$RAILWAY_VERSION" INSTALL_DIR="$RAILWAY_BINARY" sh -c "$(curl -sSL https://raw.githubusercontent.com/railwayapp/cli/master/install.sh)"
    $RAILWAY_BINARY version
    
    affected_projects=$(pnpm nx print-affected --base="$BASE_COMMIT" --head=HEAD --select=projects --type='app')
    for project in ${affected_projects//,/ }
    do
        echo "Processing: '$project'..."
        # convert hyphens to underscores
        parameterized_name=$(echo $project | tr '-' '_')
        branch_name="$(git branch --show-current)"
        # this is the key by which the required token is present in the secrets file
        env_variable=RAILWAY_TOKEN__"$parameterized_name"_"$branch_name"
        # convert the whole thing to upper case
        final_env_variable=$(echo "$env_variable" | awk '{print toupper($0)}')
        # get the actual value of the token from the secrets file
        railway_token="$(jq -r ."$final_env_variable" ./dist/secrets.json)"
        # trigger the deploy
        RAILWAY_TOKEN="$railway_token" $RAILWAY_BINARY up --detach --verbose
    done
    ```
    
    Now there is a lot going on above.
    
    The above script:
    
    - Downloads the Railway CLI binary
    - Finds all the *deployable* projects that were also affected by the changes pushed
    - Does some bash gymnastics to find the correct `RAILWAY_TOKEN`
    - Sets the `RAILWAY_TOKEN` environment variable
    - Triggers a deployment on Railway
    
    <aside>
    💡 The `--detach` flag is used here because building containers might take a lot of time which could eat up free Github Actions quota provided. You can remove it if your project allows it.
    
    </aside>
    

## Conclusion

With that, we have set up CI/CD to deploy an NX monorepo to Railway using GitHub actions. You should be able to use this as a reference to deploy your own NX monorepos. If you run into any issues, feel free to reach out to us on our [Discord](https://discord.gg/railway).

*This post is a community post thanks to IgnisDa’s. This is based off of a post on their own blog. [Click here](https://blog.ignisda.tech/working-with-nx-railway-and-cicd/) to read the original post!*