DEV Community

Cover image for Cost-effective Netlify deployments for large teams using GitHub Actions
Siddhant Khare
Siddhant Khare

Posted on

Cost-effective Netlify deployments for large teams using GitHub Actions

Netlify is a powerful platform for deploying web applications, offering seamless integration with Git repositories and automatic deployment previews for pull requests. However, for private repositories with a large number of contributors, Netlify's billing model can lead to unexpectedly high costs. Each Git contributor who sends a pull request and creates a deployment preview in a private repository is counted towards your bill, even if they're not part of your Netlify team.

In this technical guide, we'll explore how to optimize your deployment workflow to reduce Netlify costs. We'll leverage GitHub Actions to create custom deployment previews, ensuring only authorized Netlify users contribute to your bill. Additionally, we'll discuss how tools like Warp Runners (not sponsored) can further optimize your CI/CD pipeline.

Understanding Netlify's Billing Model

Netlify charges for each user who triggers a build in private repositories. Specifically:

  • Git Contributors: Any user who opens a pull request that results in a deployment preview is considered a billable user.
  • Team Members: Users explicitly added to your Netlify team are also billable.

This means that in collaborative projects, especially those with many external contributors, costs can escalate quickly. For detailed information, refer to Netlify's Roles and Permissions documentation.

Solution Overview

To mitigate these costs, we can:

  • Create Custom Deployment Previews: Use GitHub Actions to handle deployment previews instead of relying on Netlify's automatic previews.
  • Authenticate Deployments with a Single Netlify User: Use a Netlify authentication token from a single team member to perform deployments.
  • Optimize CI/CD Pipeline: Optionally integrate with services like Warp Runners to reduce build times and costs.

By implementing this solution, only the authenticated Netlify user contributes to your bill, regardless of how many contributors interact with your repository.

Implementing Custom Deployment Previews with GitHub Actions

Prerequisites

  • GitHub Repository: A private repository where you have administrative access.
  • Netlify Account: Access to your Netlify site's settings and the ability to generate personal access tokens.
  • Node.js Project: Adjust commands accordingly if you're using a different technology stack.

Step 1: Set Up Netlify Authentication

Generate a Personal Access Token

  1. Log in to Netlify: Navigate to your Netlify dashboard.
  2. Access User Settings: Click on your avatar and select User Settings.
  3. Create a Token: Under Applications > Personal Access Tokens, click New access token.
  4. Configure Token: Name the token (e.g., GitHub Actions Deploy) and set the desired scopes.
  5. Save the Token: Copy the generated token immediately, as it won't be shown again.

Add Secrets to GitHub

In your GitHub repository:

  1. Navigate to Settings: Go to Settings > Secrets and variables > Actions.
  2. Create Repository Secrets:
    • NETLIFY_AUTH_TOKEN: Paste the Netlify personal access token.
    • NETLIFY_SITE_ID: Find this in your Netlify site's settings under Site Information > Site ID.

Step 2: Create the Deployment Preview Workflow

Create a workflow file at .github/workflows/netlify-preview.yml:

name: Netlify Preview Deployment

on:
  pull_request:
    branches: [main]

jobs:
  deploy-preview:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Build project
        run: npm run build

      - name: Install Netlify CLI
        run: npm install -g netlify-cli

      - name: Deploy Preview to Netlify
        id: deploy
        run: |
          netlify deploy \
            --auth ${{ secrets.NETLIFY_AUTH_TOKEN }} \
            --site ${{ secrets.NETLIFY_SITE_ID }} \
            --dir=build \
            --message "${{ github.event.pull_request.title }}" \
            --alias "deploy-preview-${{ github.event.pull_request.number }}"
      - name: Post Deployment Comment
        uses: marocchino/sticky-pull-request-comment@v2
        with:
          number: ${{ github.event.pull_request.number }}
          header: deployment-preview
          message: |
            ### βœ… Deployment Preview Ready

            | Environment | URL |
            |-------------|-----|
            | <span aria-hidden="true">πŸ”¨</span> Latest commit | ${{ github.event.pull_request.head.sha }} |
            | Preview     | https://deploy-preview-${{ github.event.pull_request.number }}--your-site-name.netlify.app |
Enter fullscreen mode Exit fullscreen mode

Important Considerations

  • Alias Uniqueness: The alias deploy-preview-${{ github.event.pull_request.number }} ensures each preview is isolated.
  • Authentication: The deployment uses the Netlify token from a single user, preventing additional contributors from affecting billing.
  • Environment Variables: Ensure NETLIFY_AUTH_TOKEN and NETLIFY_SITE_ID are correctly set in your repository secrets.
  • Site Name Replacement: Replace your-site-name with your actual Netlify site name in the preview URL.

Step 3: Test the Deployment Preview Workflow

  1. Open a Pull Request: Create or update a pull request in your repository.
  2. Check Actions Tab: Monitor the workflow's progress in the Actions tab.
  3. Review Deployment:
    • Confirm that the Netlify deployment preview is created.
    • Verify that a comment with the preview URL is added to the pull request.

Step 4: Automate Deployment Status Updates (Optional)

To provide visual feedback in the pull request checks:

      - name: Create Deployment Status
        uses: actions/create-deployment@v1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          environment: 'Preview'
          environment_url: 'https://deploy-preview-${{ github.event.pull_request.number }}--your-site-name.netlify.app'
Enter fullscreen mode Exit fullscreen mode

This step updates the deployment status and integrates it with GitHub's deployment APIs.

Setting Up Production Deployments

For production deployments, we can use a separate workflow that triggers pushes to the main branch or manually:

Step 1: Create the production deployment workflow

Create a file at .github/workflows/netlify-production.yml:

name: Deploy Netlify Build to Production
'on':
  workflow_dispatch: null
  push:
    branches:
      - main
jobs:
  trigger:
    runs-on: ubuntu-latest
    steps:
      - name: Webhook Call to Netlify
        run: 'curl -s -X POST -d {} "${NETLIFY_BUILD_HOOK_URL}"'
        env:
          NETLIFY_BUILD_HOOK_URL: '${{ secrets.NETLIFY_BUILD_HOOK_URL }}'
Enter fullscreen mode Exit fullscreen mode

Step 2: Set Up Netlify Build Hook

  • In your Netlify site dashboard, navigate to Site Settings > Build & Deploy > Build Hooks.
  • Create a new build hook for production deployments.
  • Copy the build hook URL.
  • Add this URL as a secret (NETLIFY_BUILD_HOOK_URL) in your GitHub repository.

Step 3: Test the Workflow

Push a commit to the main branch or trigger the workflow manually. Netlify should start a production deployment of your site.

Optimizing CI/CD with Warp Runners

While GitHub Actions provides a robust platform, build times can become a bottleneck, especially with limited concurrent runners. Warp Runners offers a solution:

  • Scalable Runners: Provides additional runners to handle increased workload.
  • Cost Efficiency: Potentially reduces costs compared to upgrading GitHub Actions plans.
  • Easy Integration: Compatible with existing GitHub Actions workflows.

Integration Steps

  1. Sign Up for Warp Runners: Create an account on their platform.
  2. Configure Runners: Set up runners according to your project's needs.
  3. Update Workflows: Modify your workflows to use Warp Runners by specifying runs-on. Learn more

  4. Test Workflows: Ensure that your workflows execute correctly with the new runners.

Additional Considerations

Security

  • Access Tokens: Keep your Netlify access tokens secure. Use GitHub's encrypted secrets.
  • Least Privilege: Generate tokens with the minimum required permissions.
  • Audit Logs: Monitor Netlify and GitHub audit logs for unauthorized access.

Cleanup Deployments

Netlify retains all deployments by default. To prevent clutter:

  • Manual Cleanup: Periodically delete old deployments from the Netlify dashboard.
  • Automated Cleanup: Implement a script using Netlify's API to delete deployments associated with closed pull requests.

Environment Variables

If your build requires environment variables:

  • Define in Netlify: Set environment variables in Netlify's UI for production builds.
  • Pass in Workflows: For previews, pass variables via the CLI or use a .env file.

Example:

- name: Set Environment Variables
  run: |
    echo "API_KEY=${{ secrets.API_KEY }}" >> .env
Enter fullscreen mode Exit fullscreen mode

Conclusion

By shifting deployment previews to GitHub Actions and authenticating with a single Netlify user, you can significantly reduce Netlify billing costs associated with Git contributors in private repositories. This approach maintains the convenience of deployment previews while optimizing expenses.

Benefits Recap

  • Cost Reduction: Only one Netlify user contributes to billing.
  • Control: Full customization of the deployment pipeline.
  • Scalability: Supports a large number of contributors without additional costs.
  • Flexibility: Easily integrate with other tools and services.

By adopting these practices, you position your team to scale efficiently while keeping operational costs in check.


Stay connected and get more insights

If you found this guide helpful and are dealing with similar challenges, don't hesitate to reach out me on X. For more tech insights and updates, consider following me on GitHub. Let's innovate together!

Top comments (0)