# Reusable workflows

Our final advanced use case we would like to cover is the use of reusable workflows.

Suppose you're in a [monorepo](https://monorepo.tools/) and have the following sub-projects:

1. `web`
2. `admin`
3. `api`

All of them require the exact same CI pipeline of running unit tests and linting that we introduced in [Basics of Github Actions](/hackerschool/ci-cd-with-github-actions/basics-of-github-actions.md). If you copy-pasted the same workflow file three times, it might work, but this means that if one changes, everything needs to change. While some might argue that as the application expands, this flexibility is required to avoid a tight coupling to one type of workflow. However, for the sake of simplicity, let's suppose that this duplication is fundamentally bad for this use case. How do we go about reconciling this?

Well, this is where reusable workflows come in. They allow you to effectively define a "common workflow" that can be shared and reused by other workflows as steps. Essentially, what you're creating is custom **actions** that have not been properly published.

The [official documentation](https://docs.github.com/en/actions/sharing-automations/reusing-workflows) goes into the nitty gritty of the limitations and access of reusable workflows, so we will not cover it in this section. Instead, we will focus on setting up a very rudimentary reusable workflow for the above scenario.

So let's suppose that the original workflow looks like this:&#x20;

```yaml
# .github/workflows/web_ci.yml
name: CI/CD Pipeline
on: [pull_request, workflow_dispatch]
jobs:
  linting:
    runs-on: ubuntu-latest
    steps:
      - name: Fetch repository
        uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'yarn'
      - name: Install dependencies
        run: |
          yarn
      - name: Lint code
        run: |
          yarn lint

  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - name: Fetch repository
        uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'yarn'
      - name: Install dependencies
        run: |
          yarn
      - name: Run unit tests
        run: |
          NODE_ENV=production yarn test
```

You realize that the job steps are exactly identical, apart from the folder that these commands are being run in. We can generalize these as inputs to the reusable workflow!

```yaml
# .github/workflows/reusable-ci.yml
name: Reusable CI Workflow
on:
  workflow_call:
    inputs:
      workdir:
        description: 'Working directory'
        required: true
        type: string
jobs:
  linting:
    runs-on: ubuntu-latest
    steps:
      - name: Fetch repository
        uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
          cache: 'yarn'
          cache-dependency-path: "${{ inputs.workdir }}/yarn.lock"
      - name: Install dependencies
        working-directory: ${{ inputs.workdir }}
        run: |
          yarn
      - name: Lint code
        working-directory: ${{ inputs.workdir }}
        run: |
          yarn lint

  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - name: Fetch repository
        uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
          cache: 'yarn'
          cache-dependency-path: "${{ inputs.workdir }}/yarn.lock"
      - name: Install dependencies
        working-directory: ${{ inputs.workdir }}
        run: |
          yarn
      - name: Run unit tests
        working-directory: ${{ inputs.workdir }}
        run: |
          NODE_ENV=production yarn test
```

Essentially, the key things that had to alter were:

1. Changing the trigger event type to `workflow_call`, indicating it's a reusable workflow
2. Specifying the inputs that the reusable workflow requires, such as the `workdir` since that is the only thing that changes across variations of this CI workflow
3. Specifying the `cache-dependency-path` in the `actions/setup-node@v4` action as we need to use the `yarn.lock` files specific to each sub-project
4. Specifying the `working-directory` of each step to point to the given sub-project directory

This is all we really need to create the reusable workflow. Then, we can update our original `ci.yml` with the following:

```yaml
# .github/workflows/web_ci.yml
name: CI/CD Pipeline
on: [pull_request, workflow_dispatch]
jobs:
  ci:
    uses: <org name/username>/<repo name>/.github/workflows/reusable-ci.yml@main
    with:
      workdir: web
```

In fact, we can even inline every sub-project's CI into the same workflow:

```yaml
# .github/workflows/ci.yml
name: CI/CD Pipeline
on: [pull_request, workflow_dispatch]
jobs:
  web_ci:
    uses: <org name/username>/<repo name>/.github/workflows/reusable-ci.yml@main
    with:
      workdir: web
  admin_ci:
    uses: <org name/username>/<repo name>/.github/workflows/reusable-ci.yml@main
    with:
      workdir: admin
  api_ci:
    uses: <org name/username>/<repo name>/.github/workflows/reusable-ci.yml@main
    with:
      workdir: api
```

Incredible, we've managed to greatly simplify our CI workflow by using reusable workflows!


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.nushackers.org/hackerschool/ci-cd-with-github-actions/advanced-use-cases/reusable-workflows.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
