Skip to main content
Prerequisite: You should have read the Monorepo Architecture page to understand the basic structure of the codebase.

Overview

NCTHub uses GitHub Actions for continuous integration and continuous deployment (CI/CD) across our monorepo. These automated workflows help us maintain code quality, run tests, and deploy our applications to various environments. This page documents the key CI/CD pipelines used in the NCTHub platform and how they support our development workflow.

Workflow Categories

Our GitHub Actions workflows are organized into several categories:

1. Application Deployments

Automated deployments to Vercel for our Next.js applications:
  • Production deployments (from production branch)
  • Preview deployments (from push events to non-production branches)

2. Database Migrations

Supabase database migration workflows for different environments:
  • Production database migrations
  • Staging database migrations
  • Type generation verification

3. Package Publishing

Workflows that publish our shared packages to NPM, GitHub Packages, and JSR:
  • Types package
  • UI package
  • Supabase client package
  • ESLint config package
  • TypeScript config package
  • AI package

4. Quality Assurance

Workflows that ensure code quality:
  • Unit tests
  • Prettier formatting checks
  • CodeQL security scanning
  • CodeCov code coverage reporting

Key Workflows

Application Deployments

We use Vercel for deploying our Next.js applications. The main deployment workflows are:

Production Deployments

When code is pushed to the production branch, applications are automatically deployed to production:
We have separate production deployment workflows for each application:
  • vercel-production-hub.yaml - Main web app
All production workflows follow the same pattern but deploy to different Vercel projects, each with its own environment variables and project ID.

Preview Deployments

For non-production branches, we create preview deployments that allow developers to see their changes live before merging:
Preview deployments are set up for all our applications, providing a temporary deployment URL for each branch.

Database Migrations

We use Supabase for our database, and have automated workflows for managing database migrations:

Production Database Migrations

This workflow is manually triggered (via workflow_dispatch) to deploy database migrations to production environment. This gives us control over when migrations are applied to production.

Supabase Type Verification

We ensure that generated TypeScript types match our database schema:
This workflow runs on every push, ensuring that our TypeScript types are always in sync with the database schema.

Package Publishing

We publish several packages to make our code reusable across projects. Here’s an example workflow for the types package:
Our package publishing workflows follow a pattern:
  1. Check for a version bump in the package.json and ensure the PR title follows our convention
  2. Build and test the package
  3. Publish to multiple registries (JSR, GitHub Packages, NPM)
We have similar workflows for other packages:
  • release-ui-package.yaml
  • release-ai-package.yaml
  • release-supabase-package.yaml
  • release-eslint-config-package.yaml
  • release-typescript-config-package.yaml

Quality Assurance

We use several workflows to ensure code quality:

Unit Tests

This workflow runs on every push to main and on all pull requests, ensuring our tests pass.

Prettier Formatting

We enforce consistent code formatting with Prettier using an automated workflow that can create PRs for formatting fixes:
This workflow not only checks code formatting but also:
  1. Automatically applies Prettier fixes if formatting issues are found
  2. Creates a pull request with the fixes
  3. Adds informative comments to existing PRs if formatting issues are detected

Workflow Organization

Our GitHub Actions workflows are all defined in the .github/workflows directory of the repository. They follow a consistent naming convention:

Application Deployment Workflows

  • vercel-production-*.yaml: Production deployment workflows for each application
    • Example: vercel-production-hub.yaml
  • vercel-preview-*.yaml: Preview deployment workflows for each application
    • Example: vercel-preview-hub.yaml

Database Workflows

  • supabase-production.yaml: Production database migrations
  • supabase-staging.yaml: Staging database migrations
  • supabase-types.yaml: TypeScript type verification

Package Publishing Workflows

  • release-*-package.yaml: Package publishing workflows
    • Example: release-ui-package.yaml, release-types-package.yaml

Quality Assurance Workflows

  • turbo-unit-tests.yaml: Unit test workflow
  • prettier-check.yaml: Code formatting workflow
  • codecov.yaml: Code coverage reporting
  • codeql.yml: Security scanning

Other Utilities

  • check-and-bump-versions.yaml: Automated dependency version management
  • external-internal-packages.yaml: Managing external vs internal dependencies

Common Workflow Patterns

Our workflows follow several common patterns:

1. Conditional Execution

Many workflows check if they should run based on certain conditions:

2. Dependency Caching

Most workflows use caching to speed up builds:

3. PR-based Publishing

Package releases are triggered by merged PRs with specific title patterns:

Environment Variables and Secrets

Our workflows use several environment variables and secrets stored in GitHub:
  • VERCEL_TOKEN: For deploying to Vercel
  • VERCEL_ORG_ID: Vercel organization ID
  • VERCEL_*_PROJECT_ID: Project-specific Vercel IDs
  • SUPABASE_ACCESS_TOKEN: For authenticating with Supabase
  • *_SUPABASE_URL, *_SUPABASE_ANON_KEY, *_SUPABASE_SERVICE_KEY: Environment-specific Supabase credentials
  • NPM_TOKEN: For publishing to NPM
  • TIPTAP_PRO_TOKEN: For accessing Tiptap Pro packages
  • TURBO_TOKEN and TURBO_TEAM: For Turborepo remote caching
Never hard-code sensitive information in workflow files. Always use GitHub Secrets for API tokens, passwords, and other sensitive data.

Remote Caching with Turborepo

We leverage Turborepo’s remote caching feature in our CI pipelines to speed up builds:
This allows our CI jobs to reuse cached build artifacts from previous runs, significantly reducing build times. For large monorepos like ours, this can reduce CI times from 20+ minutes to just a few minutes when the cache is warm.

Best Practices

When working with our CI/CD pipelines, follow these best practices:

1. Test Workflows Locally

Before creating a new workflow, test it locally using act or similar tools.

2. Keep Workflows Focused

Each workflow should have a single responsibility. Split complex workflows into smaller, more focused ones.

3. Reuse Common Steps

Use composite actions or job templates to reuse common steps across workflows.

4. Monitor Workflow Performance

Regularly check workflow runs for performance issues and optimize as needed:
  1. Use GitHub’s workflow visualization to identify bottlenecks
  2. Implement caching for dependencies and build artifacts
  3. Run jobs in parallel when possible
  4. Skip unnecessary steps with conditional execution

5. Document Workflow Changes

When making significant changes to workflows, document them in pull request descriptions and update this documentation.

Troubleshooting

Common Issues

1. Workflow Timeouts

If a workflow times out, it might be due to:
  • Inefficient build process
  • Missing cache configuration
  • Network issues with external services
Try adding or improving caching strategies and optimizing build steps.

2. Failed Deployments

When deployments fail, check:
  • Build logs for errors
  • Environment variable configuration
  • Access tokens and permissions

3. Authentication Issues

For authentication problems with NPM, GitHub Packages, or Vercel:
  • Verify token permissions
  • Ensure tokens are not expired
  • Check that the token is correctly configured in GitHub Secrets

Creating New Workflows

When creating a new workflow, use this checklist:
  1. Naming Convention: Follow the established naming patterns
  2. Trigger Conditions: Define when the workflow should run
  3. Environment Variables: Include all necessary secrets and variables
  4. Optimizations: Add caching and conditional execution
  5. Error Handling: Include appropriate error handling and notifications
  6. Documentation: Add comments within the workflow file and update documentation

Further Resources