diff --git a/.github/workflows/milestone.yml b/.github/workflows/milestone.yml
new file mode 100644
index 0000000000000000000000000000000000000000..e0a8fb538900c95835c4e2c63d1fee1d8cb7d4a3
--- /dev/null
+++ b/.github/workflows/milestone.yml
@@ -0,0 +1,53 @@
+name: Milestone
+
+on:
+  pull_request_target:
+    types: [closed]
+    branches:
+      - main
+
+jobs:
+  milestone:
+    runs-on: ubuntu-latest
+
+    permissions:
+      actions: none
+      checks: none
+      contents: read
+      deployments: none
+      issues: write
+      packages: none
+      pull-requests: write
+      repository-projects: none
+      security-events: none
+      statuses: none
+
+    steps:
+      - uses: actions/github-script@v4
+        with:
+          script: |
+            if (!context.payload.pull_request.merged) {
+              console.log('PR was not merged, skipping.');
+              return;
+            }
+            if (!!context.payload.pull_request.milestone) {
+              console.log('PR has existing milestone, skipping.');
+              return;
+            }
+            milestones = await github.issues.listMilestones({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              state: 'open',
+              sort: 'due_on',
+              direction: 'asc'
+            })
+            if (milestones.data.length === 0) {
+              console.log('There are no milestones, skipping.');
+              return;
+            }
+            await github.issues.update({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              issue_number: context.payload.pull_request.number,
+              milestone: milestones.data[0].number
+            });