Build a static site and deploy to S3 + CloudFront

Build a static site and deploy to S3 + CloudFront

The classic static-site deployment is build → upload to S3 → invalidate CloudFront. Each platform has a different idiomatic way of authenticating with AWS (OIDC where supported, secret-key auth otherwise).

Conversion notes

  • OIDC integration with AWS IAM is supported on GitHub Actions and GitLab CI; CircleCI and Bitbucket fall back to access-key authentication.

Side-by-side implementation

GitHub Actions
name: deploy
on:
  push:
    branches: [main]
permissions:
  id-token: write
  contents: read
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: npm }
      - run: npm ci && npm run build
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/deploy
          aws-region: us-east-1
      - run: aws s3 sync dist/ s3://my-static-site --delete
      - run: aws cloudfront create-invalidation --distribution-id $CF_DIST_ID --paths "/*"
        env:
          CF_DIST_ID: ${{ secrets.CF_DIST_ID }}
GitLab CI
deploy:
  image: node:20
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
  id_tokens:
    GITLAB_OIDC_TOKEN:
      aud: https://sts.amazonaws.com
  script:
    - npm ci && npm run build
    - export AWS_ROLE_ARN=arn:aws:iam::123456789012:role/deploy
    - export AWS_WEB_IDENTITY_TOKEN_FILE=$GITLAB_OIDC_TOKEN
    - aws s3 sync dist/ s3://my-static-site --delete
    - aws cloudfront create-invalidation --distribution-id $CF_DIST_ID --paths "/*"
CircleCI
version: 2.1
orbs:
  aws-cli: circleci/aws-cli@4.1.3

jobs:
  deploy:
    docker: [{ image: cimg/node:20.10 }]
    steps:
      - checkout
      - run: npm ci && npm run build
      - aws-cli/setup
      - run: aws s3 sync dist/ s3://my-static-site --delete
      - run: aws cloudfront create-invalidation --distribution-id $CF_DIST_ID --paths "/*"

workflows:
  main:
    jobs:
      - deploy:
          filters:
            branches: { only: [main] }
Bitbucket Pipelines
image: node:20

pipelines:
  branches:
    main:
      - step:
          name: build
          caches: [node]
          script:
            - npm ci && npm run build
          artifacts: ['dist/**']
      - step:
          name: deploy
          script:
            - pipe: atlassian/aws-s3-deploy:1.4.0
              variables:
                AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
                AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
                AWS_DEFAULT_REGION: us-east-1
                S3_BUCKET: my-static-site
                LOCAL_PATH: dist
            - pipe: atlassian/aws-cloudfront-invalidate:0.6.1
              variables:
                AWS_ACCESS_KEY_ID: $AWS_ACCESS_KEY_ID
                AWS_SECRET_ACCESS_KEY: $AWS_SECRET_ACCESS_KEY
                AWS_DEFAULT_REGION: us-east-1
                DISTRIBUTION_ID: $CF_DIST_ID

Related Tools