CI/CD Pipeline

Continuous Integration and Continuous Deployment (CI/CD) automates your testing and deployment workflow. Learn how to set up a complete pipeline for your Amplify application.

CI/CD Overview

🔄 The CI/CD Flow

  1. Push code to your Git repository
  2. CI runs tests (lint, unit tests, type checks)
  3. Build if tests pass
  4. Deploy to the appropriate environment
  5. Notify team of success or failure

Built-in Amplify CI/CD

AWS Amplify Hosting includes basic CI/CD out of the box. When you connect your repository, Amplify automatically:

  • Triggers builds on every push
  • Runs your build commands
  • Deploys to the CDN
  • Provides build notifications

Adding Tests to the Build

Enhance the default pipeline by adding tests. Update your amplify.yml build spec:

version: 1
frontend:
  phases:
    preBuild:
      commands:
        - npm ci
    build:
      commands:
        # Run linting
        - npm run lint
        
        # Run type checking
        - npm run typecheck
        
        # Run unit tests
        - npm run test
        
        # Build the application
        - npm run build
  artifacts:
    baseDirectory: .amplify-hosting
    files:
      - '**/*'
  cache:
    paths:
      - node_modules/**/*
      - .nuxt/**/*

Add these scripts to your package.json:

{
  "scripts": {
    "dev": "nuxt dev",
    "build": "nuxt build",
    "lint": "eslint .",
    "typecheck": "nuxt typecheck",
    "test": "vitest run",
    "test:watch": "vitest"
  }
}

GitHub Actions Integration

For more control, use GitHub Actions alongside Amplify Hosting. Create .github/workflows/ci.yml:

name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Lint
        run: npm run lint
      
      - name: Type check
        run: npm run typecheck
      
      - name: Run tests
        run: npm run test
      
      - name: Build
        run: npm run build
💡
Parallel Workflows

GitHub Actions runs on every push, while Amplify Hosting deploys only when tests pass. This provides fast feedback and prevents broken deployments.

Pull Request Previews

Enable pull request previews to test changes before merging:

  1. Go to Amplify Console → Previews
  2. Click Enable previews
  3. Select which branches should generate previews

Each pull request gets a unique URL (e.g., pr-123.d1234567890abc.amplifyapp.com) for testing.

Environment-Based Pipelines

Set up different pipelines for different environments:

# .github/workflows/deploy-staging.yml
name: Deploy to Staging

on:
  push:
    branches: [develop]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      
      - name: Deploy to Staging
        run: |
          # Amplify automatically deploys when you push to connected branches
          echo "Staging deployment triggered"

Testing Strategies

Unit Tests

Test individual functions and composables:

// tests/useTodos.test.ts
import { describe, it, expect, vi } from 'vitest';

describe('useTodos', () => {
  it('should create a todo', async () => {
    // Mock the Amplify client
    vi.mock('aws-amplify/data', () => ({
      generateClient: () => ({
        models: {
          Todo: {
            create: vi.fn().mockResolvedValue({
              data: { id: '1', content: 'Test', completed: false },
            }),
          },
        },
      }),
    }));

    const { createTodo } = useTodos();
    const todo = await createTodo({ content: 'Test' });
    
    expect(todo).toBeDefined();
    expect(todo?.content).toBe('Test');
  });
});

Component Tests

// tests/TodoItem.test.ts
import { mount } from '@vue/test-utils';
import TodoItem from '~/components/TodoItem.vue';

describe('TodoItem', () => {
  it('renders todo content', () => {
    const wrapper = mount(TodoItem, {
      props: {
        todo: {
          id: '1',
          content: 'Buy groceries',
          completed: false,
        },
      },
    });

    expect(wrapper.text()).toContain('Buy groceries');
  });

  it('shows completed state', () => {
    const wrapper = mount(TodoItem, {
      props: {
        todo: {
          id: '1',
          content: 'Done task',
          completed: true,
        },
      },
    });

    expect(wrapper.find('input[type="checkbox"]').element.checked).toBe(true);
  });
});

E2E Tests

Use Playwright or Cypress for end-to-end testing:

// tests/e2e/auth.spec.ts
import { test, expect } from '@playwright/test';

test('user can sign up', async ({ page }) => {
  await page.goto('/auth/signup');
  
  await page.fill('input[type="email"]', 'test@example.com');
  await page.fill('input[type="password"]', 'SecurePassword123!');
  await page.fill('input[name="confirmPassword"]', 'SecurePassword123!');
  
  await page.click('button[type="submit"]');
  
  // Should redirect to confirmation page
  await expect(page).toHaveURL('/auth/confirm');
});

Deployment Protection Rules

Prevent accidental deployments with branch protection:

GitHub Branch Protection

  1. Go to repository Settings → Branches
  2. Add a branch protection rule for main
  3. Enable:
    • Require pull request reviews
    • Require status checks to pass
    • Require branches to be up to date

Monitoring and Alerts

Build Notifications

# .github/workflows/notify.yml
name: Notify on Deploy

on:
  workflow_run:
    workflows: ["CI"]
    types: [completed]

jobs:
  notify:
    runs-on: ubuntu-latest
    steps:
      - name: Slack Notification
        uses: slackapi/slack-github-action@v1
        with:
          channel-id: 'deployments'
          slack-message: |
            Deployment ${{ github.event.workflow_run.conclusion }}
            Branch: ${{ github.ref_name }}
            Commit: ${{ github.sha }}
        env:
          SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}

Complete Pipeline Example

# .github/workflows/pipeline.yml
name: Complete Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  NODE_VERSION: '20'

jobs:
  # Job 1: Lint and Type Check
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
      - run: npm run typecheck

  # Job 2: Unit Tests
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      - run: npm ci
      - run: npm run test
      - name: Upload coverage
        uses: codecov/codecov-action@v3

  # Job 3: Build
  build:
    needs: [lint, test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      - run: npm ci
      - run: npm run build
      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
          name: build
          path: .output

  # Job 4: E2E Tests (on PRs only)
  e2e:
    if: github.event_name == 'pull_request'
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      - run: npm ci
      - run: npx playwright install --with-deps
      - run: npm run test:e2e

Summary

  • Amplify provides built-in CI/CD with Git integration
  • Add tests to your build spec for automated testing
  • Use GitHub Actions for more complex pipelines
  • Enable PR previews for testing before merge
  • Protect branches to prevent accidental deployments
  • Set up notifications to stay informed
🎉
Course Complete!

Congratulations! You've learned how to build and deploy full-stack applications with AWS Amplify Gen 2 and Nuxt. You now have the skills to:

  • Set up Amplify projects with authentication
  • Model and manage data with DynamoDB
  • Build secure, type-safe APIs
  • Deploy to production with CI/CD