diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..d4eed9e
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,30 @@
+name: CI
+on:
+  push:
+    branches: [master]
+  pull_request:
+    branches: [master]
+jobs:
+  run-tests:
+    name: Run tests on Node.js v${{ matrix.node }}
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        node: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]
+    steps:
+      - name: Check out repository
+        uses: actions/checkout@v4
+
+      - name: Set up Node.js
+        uses: actions/setup-node@v4
+        with:
+          node-version: ${{ matrix.node }}
+
+      - name: Install dependencies
+        # Note: `npm ci` is faster and more reliable than `npm install` for CI,
+        # but it is not compatible with older versions of Node.js that we still support.
+        run: npm install
+
+      - name: Run tests
+        run: npm run test
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 83fc9fb..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-sudo: false
-os:
-  - linux
-  - osx
-  - windows
-language: node_js
-node_js:
-  - node
-  - '10'
-  - '9'
-  - '8'
diff --git a/README.md b/README.md
index 38887da..7f9f113 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# to-regex-range [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=W8YFZ425KND68) [![NPM version](https://img.shields.io/npm/v/to-regex-range.svg?style=flat)](https://www.npmjs.com/package/to-regex-range) [![NPM monthly downloads](https://img.shields.io/npm/dm/to-regex-range.svg?style=flat)](https://npmjs.org/package/to-regex-range) [![NPM total downloads](https://img.shields.io/npm/dt/to-regex-range.svg?style=flat)](https://npmjs.org/package/to-regex-range) [![Linux Build Status](https://img.shields.io/travis/micromatch/to-regex-range.svg?style=flat&label=Travis)](https://travis-ci.org/micromatch/to-regex-range)
+# to-regex-range [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=W8YFZ425KND68) [![NPM version](https://img.shields.io/npm/v/to-regex-range.svg?style=flat)](https://www.npmjs.com/package/to-regex-range) [![NPM monthly downloads](https://img.shields.io/npm/dm/to-regex-range.svg?style=flat)](https://npmjs.org/package/to-regex-range) [![NPM total downloads](https://img.shields.io/npm/dt/to-regex-range.svg?style=flat)](https://npmjs.org/package/to-regex-range) [![CI](https://github.com/micromatch/to-regex-range/actions/workflows/main.yml/badge.svg)](https://github.com/micromatch/to-regex-range/actions/workflows/main.yml)
 
 > Pass two numbers, get a regex-compatible source string for matching ranges. Validated against more than 2.78 million test assertions.