GitHub Actions gives you free compute (2,000 minutes/month on public repos, 500 on private) that can build and publish YouTube videos. Your video project lives in a repo, and pushes trigger the pipeline. It is CI/CD for content, using tools you already know.

Repository Structure

youtube-channel/
  .github/
    workflows/
      render.yml
      publish.yml
  videos/
    2026-03-28-react-hooks/
      script.md
      metadata.yml
      assets/
        recording.mp4  (git-lfs)
  templates/
    intro.mp4
    outro.mp4
    thumbnail.psd
  scripts/
    render.js
    upload.js
    validate.js

Each video gets its own directory with a script, metadata, and assets. The render and upload logic lives in shared scripts.

The Render Workflow

name: Render Video
on:
  push:
    paths: ['videos/**']
  workflow_dispatch:
    inputs:
      video_dir:
        description: 'Video directory to render'
        required: true

jobs:
  render:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - uses: actions/checkout@v4
        with:
          lfs: true

      - uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y ffmpeg
          npm ci

      - name: Determine video directory
        id: detect
        run: |
          if [ -n "${{ github.event.inputs.video_dir }}" ]; then
            echo "dir=${{ github.event.inputs.video_dir }}" >> $GITHUB_OUTPUT
          else
            echo "dir=$(git diff --name-only HEAD~1 | grep '^videos/' | head -1 | cut -d/ -f1-2)" >> $GITHUB_OUTPUT
          fi

      - name: Render
        run: node scripts/render.js "${{ steps.detect.outputs.dir }}"

      - name: Validate output
        run: node scripts/validate.js output/

      - uses: actions/upload-artifact@v4
        with:
          name: rendered-video
          path: output/
          retention-days: 7

The Publish Workflow

Separate rendering from publishing. The publish workflow can be triggered manually after review or automatically on a schedule:

name: Publish Video
on:
  workflow_dispatch:
    inputs:
      artifact_name:
        description: 'Artifact from render workflow'
        required: true
  schedule:
    - cron: '0 14 * * 1-5'  # Weekdays at 2 PM UTC

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/download-artifact@v4
        with:
          name: ${{ github.event.inputs.artifact_name || 'latest-render' }}
          path: output/

      - name: Upload to YouTube
        env:
          YOUTUBE_CLIENT_ID: ${{ secrets.YOUTUBE_CLIENT_ID }}
          YOUTUBE_CLIENT_SECRET: ${{ secrets.YOUTUBE_CLIENT_SECRET }}
          YOUTUBE_REFRESH_TOKEN: ${{ secrets.YOUTUBE_REFRESH_TOKEN }}
        run: node scripts/upload.js output/

Storing Secrets

Your YouTube OAuth credentials go in GitHub repository secrets. Never commit them to the repo. The pipeline accesses them as environment variables during the upload step. You need three secrets: the OAuth client ID, client secret, and a refresh token that you generate once via the consent flow.

Stop editing. Start shipping.

VidNo turns your coding sessions into YouTube videos — scripted, edited, thumbnailed, and uploaded. Shorts included. One command.

Try VidNo Free

Limitations and Workarounds

  • 6-hour job timeout: More than enough for most renders, but extremely long videos may need to be split
  • 14GB storage limit per artifact: Rendered 1080p videos are usually 500MB-2GB, so this is fine for typical content
  • No GPU: GitHub Actions runners are CPU-only. Use libx264 software encoding. Hardware encoding is not available
  • git-lfs bandwidth: Large video assets count against your LFS bandwidth quota. Consider using S3/R2 presigned URLs instead of LFS for source recordings

When This Pipeline Shines

This setup is ideal for developer content channels where the videos are tightly coupled to code. Tutorial channels, DevRel teams, open-source project documentation -- anywhere the video content lives naturally alongside code. The PR-based review workflow lets team members review scripts before rendering and review renders before publishing, with full audit trails in git history.