diff --git a/azure-pipelines.yml b/.github/workflows/e2e.yml
similarity index 73%
rename from azure-pipelines.yml
rename to .github/workflows/e2e.yml
index 8c51a73a8c263684126b121bdc3a66e5d111e6d3..55f2ec98406796ae4f5addd5ee834a993933ef00 100644
--- a/azure-pipelines.yml
+++ b/.github/workflows/e2e.yml
@@ -1,15 +1,18 @@
 #
-# Azure Pipelines configuration for building and testing create-react-app on Linux, Windows, and macOS.
+# GitHub Actions configuration for building and testing create-react-app on Linux, Windows, and macOS.
 #
 
-trigger:
-  - main
+name: E2E (end to end) Tests
 
-variables:
-  CI: true
-  # Overrides the Yarn and NPM cache directories so they are on the same drive as the source. This helps improve build performance on Windows hosted agents.
-  YARN_CACHE_FOLDER: $(Build.SourcesDirectory)/../yarn-cache
-  NPM_CONFIG_CACHE: $(Build.SourcesDirectory)/../npm-cache
+on:
+  push:
+    branches:
+      - main
+  pull_request:
+    branches:
+      - main
+
+env:
   # Sets TEMP to be on the same drive as the cloned source on Windows. This avoids test scripts that "cd" into a directory under TEMP from failing because this directory is on a different drive from the current directory.
   VSTS_OVERWRITE_TEMP: True
   CRA_INTERNAL_TEST: true
@@ -18,24 +21,27 @@ variables:
 # Simple test suite
 # ******************************************************************************
 jobs:
-  - template: azure-pipelines-test-job.yml
-    parameters:
+  simple:
+    uses: ./.github/workflows/test-job.yml
+    with:
       name: Simple
       testScript: tasks/e2e-simple.sh
 
   # ******************************************************************************
   # Installs test suite
   # ******************************************************************************
-  - template: azure-pipelines-test-job.yml
-    parameters:
+  installs:
+    uses: ./.github/workflows/test-job.yml
+    with:
       name: Installs
       testScript: tasks/e2e-installs.sh
 
   # ******************************************************************************
   # Kitchensink test suite
   # ******************************************************************************
-  - template: azure-pipelines-test-job.yml
-    parameters:
+  kitchensink:
+    uses: ./.github/workflows/test-job.yml
+    with:
       name: Kitchensink
       testScript: tasks/e2e-kitchensink.sh
 
@@ -65,13 +71,14 @@ jobs:
   # ******************************************************************************
   # Old Node test suite
   # ******************************************************************************
-  - job: OldNode
-    pool:
-      vmImage: ubuntu-latest
+  oldnode:
+    runs-on: ubuntu-latest
     steps:
-      - task: NodeTool@0
-        inputs:
-          versionSpec: 8.x
-        displayName: 'Install Node.js 8.x'
-      - bash: tasks/e2e-old-node.sh
-        displayName: 'Run tests'
+      - uses: actions/checkout@v2
+      - uses: actions/setup-node@v2
+        with:
+          node-version: 8
+          cache: 'npm'
+        name: 'Install Node.js 8.x'
+      - run: tasks/e2e-old-node.sh
+        name: 'Run tests'
diff --git a/.github/workflows/test-job.yml b/.github/workflows/test-job.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ade1b72d05a4ce27669e7fde21f321e14b0ff032
--- /dev/null
+++ b/.github/workflows/test-job.yml
@@ -0,0 +1,46 @@
+#
+# GitHub Actions workflow for building and testing create-react-app on Linux, Windows, and macOS.
+#
+
+on:
+  workflow_call:
+    inputs:
+      name:
+        default: ''
+        required: true
+        type: string
+      testScript:
+        default: ''
+        required: true
+        type: string
+
+jobs:
+  build:
+    name: ${{ inputs.name }}
+    strategy:
+      matrix:
+        node-version: [14.x, 16.x]
+    runs-on: ubuntu-latest
+    steps:
+      - run: |
+          git config --global core.autocrlf false
+          git config --global user.name "Create React App"
+          git config --global user.email "cra@email.com"
+        name: 'Initialize Git config'
+
+      - uses: actions/checkout@v2
+
+      - uses: actions/setup-node@v2
+        with:
+          node-version: ${{ matrix.node-version }}
+          cache: 'npm'
+        name: 'Install Node.js'
+
+      - run: npm i -g npm@8
+        name: 'Update npm to v8'
+
+      - run: npm ci
+        name: 'Run npm ci'
+
+      - run: ${{ inputs.testScript }}
+        name: 'Run tests'
diff --git a/README.md b/README.md
index 91283e853e4c7c803435367d6194c10fec48c8c4..7b7cced3bbfe5b7480cba0c822a8f014b67398c1 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# Create React App [![Build Status](https://dev.azure.com/facebook/create-react-app/_apis/build/status/facebook.create-react-app?branchName=main)](https://dev.azure.com/facebook/create-react-app/_build/latest?definitionId=1&branchName=main) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-green.svg)](https://github.com/facebook/create-react-app/blob/main/CONTRIBUTING.md)
+# Create React App [![Build Status](https://github.com/facebook/create-react-app/actions/workflows/e2e.yml/badge.svg?branch=main)](https://github.com/facebook/create-react-app/actions/workflows/e2e.yml?query=branch:main) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-green.svg)](https://github.com/facebook/create-react-app/blob/main/CONTRIBUTING.md)
 
 <img alt="Logo" align="right" src="https://create-react-app.dev/img/logo.svg" width="20%" />
 
diff --git a/azure-pipelines-test-job.yml b/azure-pipelines-test-job.yml
deleted file mode 100644
index cdf3f4dacfd36719dc5d8cdd37dc2f095c28d79a..0000000000000000000000000000000000000000
--- a/azure-pipelines-test-job.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# Azure Pipelines job for building and testing create-react-app on Linux, Windows, and macOS.
-#
-
-parameters:
-  name: ''
-  testScript: ''
-  configurations:
-    LinuxNode14: { vmImage: 'ubuntu-latest', nodeVersion: 14.x }
-    LinuxNode16: { vmImage: 'ubuntu-latest', nodeVersion: 16.x }
-
-jobs:
-  - job: ${{ parameters.name }}
-    strategy:
-      matrix:
-        ${{ insert }}: ${{ parameters.configurations }}
-    pool:
-      vmImage: $(vmImage)
-    steps:
-      - script: |
-          git config --global core.autocrlf false
-          git config --global user.name "Create React App"
-          git config --global user.email "cra@email.com"
-        displayName: 'Initialize Git config'
-
-      - checkout: self
-        path: create-react-app
-
-      - task: NodeTool@0
-        inputs:
-          versionSpec: $(nodeVersion)
-        displayName: 'Install Node.js'
-
-      - script: npm i -g npm@8
-        displayName: 'Update npm to v8'
-
-      - script: npm ci
-        displayName: 'Run npm ci'
-
-      - bash: ${{ parameters.testScript }}
-        displayName: 'Run tests'