Monorepos are powerful, but when it comes to deploying them to platforms like Koyeb, Netlify, and Vercel, things can get messy fast.

In this article, I’ll walk you through a common issue with monorepo deployments and how I solved it using GitHub Actions, including how to disable auto-deployments and trigger deploys only when specific apps/packages change.

🧠 The Problem

Modern deployment platforms listen to your repo and redeploy your app every time anything changes. This works fine for single-app projects.

But with monorepos? Not so much.

Imagine this:

  • You have a monorepo with multiple packages or apps.
  • You deploy only one package to a platform like Vercel.
  • Then you change a file in another unrelated package.
  • The platform still triggers a redeploy 😩

That’s a waste of resources, time, and can cause unnecessary build failures.

We want this instead:

Only deploy when files relevant to the deployed app/package are changed.

🗂️ Example Project Structure

To demonstrate the solution, let’s use a simple monorepo setup like this:

monorepo/
├── netlify-frontend/       # Deployed to Netlify
├── vercel-nextjs-app/      # Deployed to Vercel
├── koyeb-server/           # Deployed to Koyeb
└── shared/                 # Shared code across apps (not deployed directly)

🔑 Generating Deployment Credentials

Before we disable auto-deploys, we need a way to trigger deploys manually — using webhooks or API keys.

Vercel – Deployment Webhook

  • Navigate to your project page → SettingsGitDeploy HooksCreate Hook

Netlify – Build Hook

  • Go to your site dashboard → Site ConfigurationBuild & DeployBuild HooksAdd Build Hook

Koyeb – API Key

Koyeb doesn’t use build hooks, but instead offers an API you can use to trigger deployments programmatically.

  • Open your Koyeb dashboard → SettingsAPICreate API Token

🚫 Disabling Auto-Deployments

Once we have the credentials, we can safely disable automatic deployments.

Netlify

  • Go to your site dashboard → Deploys → Click Lock to stop auto publishing

Vercel

To prevent auto-deploys from Git integration:

  • Navigate to your project page → SettingsGitIgnored Build Step → Select "Don't build anything"

Koyeb

To disable Git auto-deploy:

  • Go to your service page → SettingsConfigure Deployment Source → Uncheck the Autodeploy checkbox

⚙️ Step 2: GitHub Actions Workflow

Now that auto-deploy is off, we take control.

Here’s how the GitHub Actions workflow works:

  • It checks what files or folders have changed in the commit.
  • If the changed files are part of netlify-frontend/, vercel-nextjs-app/, or koyeb-server/, it triggers the corresponding deployment via webhook/API.

Here’s a sample workflow:

# .github/workflows/deploy.yml

name: Conditional Deploy

on:
  push:
    branches:
      - master  # Triggers workflow only on push to master branch

jobs:
  detect-changes:
    runs-on: ubuntu-latest
    outputs:
      # Expose matched filters as outputs for use in other jobs
      netlify_frontend_changed: ${{ steps.filter.outputs.netlify_frontend }}
      vercel_nextjs_app_changed: ${{ steps.filter.outputs.vercel_nextjs_app }}
      koyeb_server_changed: ${{ steps.filter.outputs.koyeb_server }}
      shared_changed: ${{ steps.filter.outputs.shared }}

    steps:
      - uses: actions/checkout@v3  # Checkout the repository code

      - name: Check for changes
        id: filter
        uses: dorny/paths-filter@v3  # Detect which paths have changed
        with:
          filters: |
            netlify_frontend:
              - 'netlify-frontend/**'
            vercel_nextjs_app:
              - 'vercel-nextjs-app/**'
            koyeb_server:
              - 'koyeb-server/**'
            shared:
              - 'shared/**'

  deploy-netlify-frontend:
    needs: detect-changes
    if: needs.detect-changes.outputs.netlify_frontend_changed == 'true' || needs.detect-changes.outputs.shared_changed == 'true'
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Netlify Deploy
        run: |
          curl -X POST -d '{}' https://api.netlify.com/build_hooks/${{ secrets.NETLIFY_FRONTEND_DEPLOY_KEY }}
        # Uses Netlify build hook URL to trigger deploy

  deploy-nextjs-app:
    needs: detect-changes
    if: needs.detect-changes.outputs.vercel_nextjs_app_changed == 'true' || needs.detect-changes.outputs.shared_changed == 'true'
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Vercel Deploy
        run: |
          curl -X POST -d '{}' https://api.vercel.com/v1/integrations/deploy/${{ secrets.VERCEL_APP_DEPLOY_KEY }}
        # Uses Vercel deploy webhook to trigger a deploy

  deploy-koyeb-server:
    needs: detect-changes
    if: needs.detect-changes.outputs.koyeb_server_changed == 'true' || needs.detect-changes.outputs.shared_changed == 'true'
    runs-on: ubuntu-latest
    steps:
      - name: Install Koyeb CLI
        run: |
          curl -fsSL https://raw.githubusercontent.com/koyeb/koyeb-cli/master/install.sh | sh
          echo "$HOME/.koyeb/bin" >> $GITHUB_PATH
        # Installs the Koyeb CLI and adds it to the path

      - name: Verify CLI
        run: koyeb version
        # Optional step to verify the CLI is working

      - name: Trigger redeploy
        run: |
          koyeb service redeploy ${{ secrets.KOYEB_SERVICE_NAME }} \
            --app ${{ secrets.KOYEB_APP_NAME }} \
            --token ${{ secrets.KOYEB_API_TOKEN }}
        # Redeploys the Koyeb service using the CLI and secret tokens

🎯 Final Thoughts

With this setup:

✅ You stop wasting build minutes

✅ You only deploy what's actually changed

✅ You fully control the pipeline with GitHub Actions

Let your monorepo breathe — deploy smarter, not harder.