<html><head><link rel="canonical" href="https://www.jetbrains.com/help/writerside/deploy-docs-to-github-pages.html.md/" data-react-helmet="true"/></head><body># Build and publish on GitHub

If your documentation sources are hosted on [GitHub](https://github.com/), you can use [GitHub Actions](https://github.com/features/actions) to build your documentation website and deploy it to [GitHub Pages](https://pages.github.com/).

&gt; **Tip:**
&gt; For more information about hosting your documentation sources on GitHub, see [Git integration](git-integration.html).

Procedure: Set up a GitHub Actions workflow

1. In the root of your project, create the `.github/workflows/` directory to store [workflow](https://docs.github.com/en/actions/using-workflows) files.

2. In the `.github/workflows/` directory, create a new YAML file named `build-docs.yml`.

Use this file to define the automated jobs that build, test, and publish your documentation.

## Build documentation website

The following sample workflow will trigger on every push to the `main` branch in the repository and build the [starter project](projects.html), where the default module name is `Writerside` and the default instance ID is `hi`:

```YAML
name: Build documentation

on:
  push:
    branches: ["main"]
  workflow_dispatch:

env:
  INSTANCE: 'Writerside/hi'
  DOCKER_VERSION: 'XXX.YYYYY'
  # IS_GROUP: 'true'  # Uncomment to build a group

jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      algolia_artifact: ${{ steps.define-ids.outputs.algolia_artifact }}
      artifact: ${{ steps.define-ids.outputs.artifact }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Define instance id and artifacts
        id: define-ids
        run: |
          INSTANCE=${INSTANCE#*/}
          INSTANCE_ID_UPPER=$(echo "$INSTANCE" | tr '[:lower:]' '[:upper:]')
          ARTIFACT="webHelp${INSTANCE_ID_UPPER}2-all.zip"
          ALGOLIA_ARTIFACT="algolia-indexes-${INSTANCE_ID_UPPER}.zip"

          # Print the values
          echo "INSTANCE_ID_UPPER: $INSTANCE_ID_UPPER"
          echo "ARTIFACT: $ARTIFACT"
          echo "ALGOLIA_ARTIFACT: $ALGOLIA_ARTIFACT"

          # Set the environment variables and outputs
          echo "INSTANCE_ID_UPPER=$INSTANCE_ID_UPPER" &gt;&gt; $GITHUB_ENV
          echo "ARTIFACT=$ARTIFACT" &gt;&gt; $GITHUB_ENV
          echo "ALGOLIA_ARTIFACT=$ALGOLIA_ARTIFACT" &gt;&gt; $GITHUB_ENV
          echo "artifact=$ARTIFACT" &gt;&gt; $GITHUB_OUTPUT
          echo "algolia_artifact=$ALGOLIA_ARTIFACT" &gt;&gt; $GITHUB_OUTPUT

      - name: Build docs using Writerside Docker builder
        uses: JetBrains/writerside-github-action@v4
        with:
          instance: ${{ env.INSTANCE }}
          docker-version: ${{ env.DOCKER_VERSION }}

      - name: Save artifact with build results
        uses: actions/upload-artifact@v4
        with:
          name: docs
          path: |
            artifacts/${{ steps.define-ids.outputs.artifact }}
            artifacts/report.json
            artifacts/${{ steps.define-ids.outputs.algolia_artifact }}
          retention-days: 7
```

If necessary, set the correct values for environment variables:

env.INSTANCE
: The name of the [module](projects.html#help_module) and [instance](instances.html) ID separated by a slash. The module name is the directory with  `[writerside.cfg](writerside-cfg.html)` . It is designated by the icon ![module icon](https://resources.jetbrains.com/help/img/writerside/module.svg) in the Project tool window.
:
:
:
: For example, the default module name in a starter project is `Writerside` and the instance ID is `hi`. So in this case, set the variable to `Writerside/hi`.
:
:
:
: &gt; **Note:**
: &gt; If you want to [build multiple instances](build-groups.html), set `IS_GROUP: 'true'` and make sure the `INSTANCE` variable points to the necessary build group.
: &gt;
: &gt;
: &gt;
: &gt; Also, in this case, save the artifacts to `path: artifacts/*`.

env.DOCKER_VERSION
: The version of the Writerside Docker builder to use for generating the documentation artifacts. The current latest version is 2026.08.0328.
:
:
:
: When you update to a newer version of Writerside, set the new Docker builder version to ensure results similar to what you see in the local preview and local builds.

After you commit and push `build-docs.yml`, the `Build documentation` workflow will automatically trigger and run the `build` job. Go to the project repository on GitHub and open the Actions tab to see the workflow and the produced artifacts.

The `build` job runs on the latest Ubuntu virtual machine and consists of three steps:

* Checkout the project repository using the [actions/checkout@v4](https://github.com/marketplace/actions/checkout) action.

* Generate the documentation website using the [JetBrains/writerside-github-action@v4](https://github.com/marketplace/actions/build-writerside-docs-using-docker) action.

* Save the generated website archive using the [actions/upload-artifact@v4](https://github.com/marketplace/actions/upload-a-build-artifact) action as part of the `docs` artifact.

## Test produced artifacts

The Writerside builder produces a report with all problems that occurred during the build. You can view this report manually or configure a separate job that automatically checks the report and fails the workflow if it contains errors.

Modify the workflow file from the previous example and add `report.json` to the `docs` artifact that the `build` job produces. Also, add the `test` job to the workflow.

```YAML
name: Build documentation

on:
  push:
    branches: ["main"]
  workflow_dispatch:

env:
  INSTANCE: 'Writerside/hi'
  DOCKER_VERSION: 'XXX.YYYYY'
  # IS_GROUP: 'true'  # Uncomment to build a group

jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      algolia_artifact: ${{ steps.define-ids.outputs.algolia_artifact }}
      artifact: ${{ steps.define-ids.outputs.artifact }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Define instance id and artifacts
        id: define-ids
        run: |
          INSTANCE=${INSTANCE#*/}
          INSTANCE_ID_UPPER=$(echo "$INSTANCE" | tr '[:lower:]' '[:upper:]')
          ARTIFACT="webHelp${INSTANCE_ID_UPPER}2-all.zip"
          ALGOLIA_ARTIFACT="algolia-indexes-${INSTANCE_ID_UPPER}.zip"

          # Print the values
          echo "INSTANCE_ID_UPPER: $INSTANCE_ID_UPPER"
          echo "ARTIFACT: $ARTIFACT"
          echo "ALGOLIA_ARTIFACT: $ALGOLIA_ARTIFACT"

          # Set the environment variables and outputs
          echo "INSTANCE_ID_UPPER=$INSTANCE_ID_UPPER" &gt;&gt; $GITHUB_ENV
          echo "ARTIFACT=$ARTIFACT" &gt;&gt; $GITHUB_ENV
          echo "ALGOLIA_ARTIFACT=$ALGOLIA_ARTIFACT" &gt;&gt; $GITHUB_ENV
          echo "artifact=$ARTIFACT" &gt;&gt; $GITHUB_OUTPUT
          echo "algolia_artifact=$ALGOLIA_ARTIFACT" &gt;&gt; $GITHUB_OUTPUT

      - name: Build docs using Writerside Docker builder
        uses: JetBrains/writerside-github-action@v4
        with:
          instance: ${{ env.INSTANCE }}
          docker-version: ${{ env.DOCKER_VERSION }}

      - name: Save artifact with build results
        uses: actions/upload-artifact@v4
        with:
          name: docs
          path: |
            artifacts/${{ steps.define-ids.outputs.artifact }}
            artifacts/report.json
            artifacts/${{ steps.define-ids.outputs.algolia_artifact }}
          retention-days: 7
  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          name: docs
          path: artifacts

      - name: Test documentation
        uses: JetBrains/writerside-checker-action@v1
        with:
          instance: ${{ env.INSTANCE }}
```

After you commit and push this workflow, the `test` job will run only if the `build` job finished successfully, and it consists of the following steps:

* Download the `docs` artifact into `artifacts` using the [actions/download-artifact@v4](https://github.com/marketplace/actions/download-a-build-artifact) action.

* Parse `report.json` using the [JetBrains/writerside-checker-action@v1](https://github.com/marketplace/actions/writerside-doc-errors-checker) action, which fails the job if there are errors in the build report.

## Build, test, and publish to GitHub Pages

You can publish the produced artifacts manually or in a separate workflow. However, if you want continuous delivery automation, configure a job in the same workflow that will deploy every successfully built and tested artifact to GitHub Pages.

Procedure: Enable publishing to GitHub Pages

* Open the repository on GitHub, click Settings, then click Pages under Code and automation, and then select GitHub Actions as the Source under Build and deployment.

Procedure: Configure the web path for images

* In the  `[writerside.cfg](writerside-cfg.html)`  file, set the `[web-path](writerside-cfg.html#images_web-path)` parameter in the `[&lt;images&gt;](writerside-cfg.html#images)` element to the GitHub repository name, for example:

```XML
<ihp version="2.0">
    <topics dir="topics">
    <images dir="images" web-path="my-docs-repo">
    <instance src="hi.tree">
</instance></images></topics></ihp>
```

Modify the workflow file from the previous example and assign write permissions for the `id-token` and `pages` scopes in your workflow. Also, add the `deploy` job to the workflow.

```YAML
name: Build documentation

on:
  push:
    branches: ["main"]
  workflow_dispatch:

permissions:
  contents: read
  id-token: write
  pages: write

env:
  INSTANCE: 'Writerside/hi'
  DOCKER_VERSION: 'XXX.YYYYY'
  # IS_GROUP: 'true'  # Uncomment to build a group

jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      algolia_artifact: ${{ steps.define-ids.outputs.algolia_artifact }}
      artifact: ${{ steps.define-ids.outputs.artifact }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Define instance id and artifacts
        id: define-ids
        run: |
          INSTANCE=${INSTANCE#*/}
          INSTANCE_ID_UPPER=$(echo "$INSTANCE" | tr '[:lower:]' '[:upper:]')
          ARTIFACT="webHelp${INSTANCE_ID_UPPER}2-all.zip"
          ALGOLIA_ARTIFACT="algolia-indexes-${INSTANCE_ID_UPPER}.zip"

          # Print the values
          echo "INSTANCE_ID_UPPER: $INSTANCE_ID_UPPER"
          echo "ARTIFACT: $ARTIFACT"
          echo "ALGOLIA_ARTIFACT: $ALGOLIA_ARTIFACT"

          # Set the environment variables and outputs
          echo "INSTANCE_ID_UPPER=$INSTANCE_ID_UPPER" &gt;&gt; $GITHUB_ENV
          echo "ARTIFACT=$ARTIFACT" &gt;&gt; $GITHUB_ENV
          echo "ALGOLIA_ARTIFACT=$ALGOLIA_ARTIFACT" &gt;&gt; $GITHUB_ENV
          echo "artifact=$ARTIFACT" &gt;&gt; $GITHUB_OUTPUT
          echo "algolia_artifact=$ALGOLIA_ARTIFACT" &gt;&gt; $GITHUB_OUTPUT

      - name: Build docs using Writerside Docker builder
        uses: JetBrains/writerside-github-action@v4
        with:
          instance: ${{ env.INSTANCE }}
          docker-version: ${{ env.DOCKER_VERSION }}

      - name: Save artifact with build results
        uses: actions/upload-artifact@v4
        with:
          name: docs
          path: |
            artifacts/${{ steps.define-ids.outputs.artifact }}
            artifacts/report.json
            artifacts/${{ steps.define-ids.outputs.algolia_artifact }}
          retention-days: 7
  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          name: docs
          path: artifacts

      - name: Test documentation
        uses: JetBrains/writerside-checker-action@v1
        with:
          instance: ${{ env.INSTANCE }}
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    needs: [build, test]
    runs-on: ubuntu-latest
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          name: docs
          path: artifacts

      - name: Unzip artifact
        run: unzip -O UTF-8 -qq "artifacts/${{ needs.build.outputs.artifact }}" -d dir

      - name: Setup Pages
        uses: actions/configure-pages@v4

      - name: Package and upload Pages artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: dir

      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4
```

After you commit and push this workflow, the `deploy` job will run only if both `build` and `test` finish successfully, and it consists of the following steps:

* Download the `docs` artifact using the [actions/download-artifact@v4](https://github.com/marketplace/actions/download-a-build-artifact) action.

* Unzip the website archive using the `unzip` command.

* Enable GitHub Pages using the [actions/configure-pages@v4](https://github.com/marketplace/actions/configure-github-pages) action.

* Package and upload an artifact that can be deployed to GitHub Pages using the [actions/upload-pages-artifact@v3](https://github.com/marketplace/actions/upload-github-pages-artifact) action.

* Deploy the artifact to GitHub Pages using the [actions/deploy-pages@v4](https://github.com/marketplace/actions/deploy-github-pages-site).

If the workflow is successful, the `deploy` job will output the URL to the published documentation.

## Upload search indexes

If you also [configure Algolia search](algolia-search.html#github), you can modify the workflow further and add the `publish-indexes` job that will automatically update the search indexes after a successful deployment.

You will also need to add Algolia indexes to the `docs` artifact that the `build` job produces, and specify the following additional environment variables:

env.ALGOLIA_APP_NAME
: Algolia application ID

env.ALGOLIA_INDEX_NAME
: Name of Algolia index

env.CONFIG_JSON_PRODUCT
: Help instance ID from the  [tree file](help-modules.html#tree-file)  or the value of the `web-path` attribute specified in  `[writerside.cfg](writerside-cfg.html)`  if it is different from the ID

env.CONFIG_JSON_VERSION
: Help instance version (usually the same as the branch name) specified in  `[writerside.cfg](writerside-cfg.html)`

&gt; **Note:**
&gt; You can find the application ID and API keys in your Algolia account settings under [API Keys](https://dashboard.algolia.com/account/api-keys).
&gt;
&gt;
&gt;
&gt; Specify your private API key as a secret. The workflow will reference it via `${{ secrets.ALGOLIA_KEY }}`.

For example:

```YAML
ALGOLIA_APP_NAME: 'NLAGB2LZHU'
ALGOLIA_INDEX_NAME: 'MY_INDEX'
CONFIG_JSON_PRODUCT: 'HI'
CONFIG_JSON_VERSION: '1.0'
```

Here is how it all comes together in a single workflow file:

```YAML
name: Build documentation

on:
  push:
    branches: ["main"]
  workflow_dispatch:

permissions:
  contents: read
  id-token: write
  pages: write

env:
  INSTANCE: 'Writerside/hi'
  DOCKER_VERSION: 'XXX.YYYYY'
  # IS_GROUP: 'true'  # Uncomment to build a group
  ALGOLIA_APP_NAME: 'NLAGB2LZHU'
  ALGOLIA_INDEX_NAME: 'MY_INDEX'
  CONFIG_JSON_PRODUCT: 'HI'
  CONFIG_JSON_VERSION: '1.0'

jobs:
  build:
    runs-on: ubuntu-latest
    outputs:
      algolia_artifact: ${{ steps.define-ids.outputs.algolia_artifact }}
      artifact: ${{ steps.define-ids.outputs.artifact }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Define instance id and artifacts
        id: define-ids
        run: |
          INSTANCE=${INSTANCE#*/}
          INSTANCE_ID_UPPER=$(echo "$INSTANCE" | tr '[:lower:]' '[:upper:]')
          ARTIFACT="webHelp${INSTANCE_ID_UPPER}2-all.zip"
          ALGOLIA_ARTIFACT="algolia-indexes-${INSTANCE_ID_UPPER}.zip"

          # Print the values
          echo "INSTANCE_ID_UPPER: $INSTANCE_ID_UPPER"
          echo "ARTIFACT: $ARTIFACT"
          echo "ALGOLIA_ARTIFACT: $ALGOLIA_ARTIFACT"

          # Set the environment variables and outputs
          echo "INSTANCE_ID_UPPER=$INSTANCE_ID_UPPER" &gt;&gt; $GITHUB_ENV
          echo "ARTIFACT=$ARTIFACT" &gt;&gt; $GITHUB_ENV
          echo "ALGOLIA_ARTIFACT=$ALGOLIA_ARTIFACT" &gt;&gt; $GITHUB_ENV
          echo "artifact=$ARTIFACT" &gt;&gt; $GITHUB_OUTPUT
          echo "algolia_artifact=$ALGOLIA_ARTIFACT" &gt;&gt; $GITHUB_OUTPUT

      - name: Build docs using Writerside Docker builder
        uses: JetBrains/writerside-github-action@v4
        with:
          instance: ${{ env.INSTANCE }}
          docker-version: ${{ env.DOCKER_VERSION }}

      - name: Save artifact with build results
        uses: actions/upload-artifact@v4
        with:
          name: docs
          path: |
            artifacts/${{ steps.define-ids.outputs.artifact }}
            artifacts/report.json
            artifacts/${{ steps.define-ids.outputs.algolia_artifact }}
          retention-days: 7
  test:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          name: docs
          path: artifacts

      - name: Test documentation
        uses: JetBrains/writerside-checker-action@v1
        with:
          instance: ${{ env.INSTANCE }}
  deploy:
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    needs: [build, test]
    runs-on: ubuntu-latest
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          name: docs
          path: artifacts

      - name: Unzip artifact
        run: unzip -O UTF-8 -qq "artifacts/${{ needs.build.outputs.artifact }}" -d dir

      - name: Setup Pages
        uses: actions/configure-pages@v4

      - name: Package and upload Pages artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: dir

      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4
  publish-indexes:
    needs: [build, test, deploy]
    runs-on: ubuntu-latest
    container:
      image: registry.jetbrains.team/p/writerside/builder/algolia-publisher:latest
    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: docs
          path: artifacts
      - name: Unzip Algolia artifact
        run: unzip -O UTF-8 -qq "artifacts/${{ needs.build.outputs.algolia_artifact }}" -d algolia-indexes
      - name: Update Algolia Index
        run: |
          if [ -z "${{ secrets.ALGOLIA_KEY }}" ]; then
            echo "ALGOLIA_KEY secret is not set in GitHub Secrets"
            exit 1
          else
            env "algolia-key=${{ secrets.ALGOLIA_KEY }}" java -jar /opt/builder/help-publication-agent.jar \
            update-index \
            --application-name ${{ env.ALGOLIA_APP_NAME }} \
            --index-name ${{ env.ALGOLIA_INDEX_NAME }} \
            --product ${{ env.CONFIG_JSON_PRODUCT }} \
            --version ${{ env.CONFIG_JSON_VERSION }} \
            --index-directory algolia-indexes/ \
            2&gt;&amp;1 | tee algolia-update-index-log.txt
          fi
```

## Build to PDF

You can configure a separate workflow or a job in an existing workflow to produce a PDF artifact. Here is an example of a separate workflow with a `build-pdf` job that produces a PDF:

```YAML
name: Build to PDF

on:
  push:
    branches: ["main"]
  workflow_dispatch:

env:
  INSTANCE: 'Writerside/hi'
  DOCKER_VERSION: '2026.08.0328'
  PDF: 'PDF.xml'

jobs:
  build-pdf:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Define instance ID
        run: |
          INSTANCE_ID="${INSTANCE#*/}"
          INSTANCE_ID_UPPER=$(echo "$INSTANCE_ID" | tr '[:lower:]' '[:upper:]')
          echo "INSTANCE_ID_UPPER=$INSTANCE_ID_UPPER" &gt;&gt; $GITHUB_ENV
          echo "Extracted ID: $INSTANCE_ID_UPPER"

      - name: Build Writerside docs using Docker
        uses: JetBrains/writerside-github-action@v4
        with:
          instance: ${{ env.INSTANCE }}
          docker-version: ${{ env.DOCKER_VERSION }}
          pdf: ${{ env.PDF }}

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: artifact
          path: |
            artifacts/pdfSource${{ env.INSTANCE_ID_UPPER }}.pdf
            artifacts/pdfSource${{ env.INSTANCE_ID_UPPER }}.html
          retention-days: 7
```

&gt; **Note:**
&gt; You should have the `PDF.xml` file in the  [cfg directory](help-modules.html#build-config-dir) . For more information, see [Export to PDF](export-to-pdf.html).

</body></html>