diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..164f902
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,45 @@
+name: CI
+on:
+  push:
+    branches:
+      - '*'
+    tags:
+      - 'v*'
+  pull_request:
+    branches:
+      - master
+jobs:
+  test:
+    runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        scala_version: [2.13.2, 2.12.11]
+        platform: [jvm, js]
+    env:
+      PLATFORM: ${{ matrix.platform }}
+    steps:
+    - uses: actions/checkout@v4
+      with:
+        persist-credentials: false
+    - name: Coursier cache
+      uses: coursier/cache-action@v6
+    - uses: coursier/setup-action@v1
+      with:
+        jvm: zulu:8.0.432
+        apps: sbt scala
+
+    - name: JS Tests
+      if: ${{ matrix.platform != 'js' }}
+      run: sbt "++${{ matrix.scala_version }}" testsJS/test propsJS/test
+
+    - name: JVM Tests
+      if: ${{ matrix.platform != 'jvm' }}
+      run: sbt "++${{ matrix.scala_version }}" testsJVM/test propsJVM/test
+
+    - name: Clean up
+      run: |
+        rm -rf "$HOME/.ivy2/local" || true
+        find $HOME/Library/Caches/Coursier/v1        -name "ivydata-*.properties" -delete || true
+        find $HOME/.ivy2/cache                       -name "ivydata-*.properties" -delete || true
+        find $HOME/.cache/coursier/v1                -name "ivydata-*.properties" -delete || true
+        find $HOME/.sbt                              -name "*.lock"               -delete || true
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index de79758..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,43 +0,0 @@
-matrix:
-  include:
-    - scala: 2.13.2
-      language: scala
-      jdk: openjdk8
-      env: PLATFORM="jvm"
-      script: sbt "++2.13.2" coverage testsJVM/test propsJVM/test coverageReport && codecov
-
-    - scala: 2.13.2
-      language: scala
-      jdk: openjdk8
-      env: PLATFORM="js"
-      script: sbt "++2.13.2" testsJS/test propsJS/test
-
-    - scala: 2.12.11
-      language: scala
-      jdk: openjdk8
-      env: PLATFORM="jvm"
-      script: sbt "++2.12.11" testsJVM/test propsJVM/test
-
-    - scala: 2.12.11
-      language: scala
-      jdk: openjdk8
-      env: PLATFORM="js"
-      script: sbt "++2.12.11" testsJS/test propsJS/test
-
-install:
- - pip install --user codecov
-
-cache:
-  directories:
-  - $HOME/.cache
-  - $HOME/.coursier
-  - $HOME/.ivy2/cache
-  - $HOME/.m2
-  - $HOME/.nvm
-  - $HOME/.sbt
-
-before_cache:
-  - du -h -d 1 $HOME/.ivy2/cache
-  - du -h -d 2 $HOME/.sbt/
-  - find $HOME/.sbt -name "*.lock" -type f -delete
-  - find $HOME/.ivy2/cache -name "ivydata-*.properties" -type f -delete
diff --git a/README.md b/README.md
index da9001b..6cbc17a 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-[![Build Status](https://api.travis-ci.org/non/antimirov.svg)](https://travis-ci.org/non/antimirov)
+[![CI](https://github.com/non/antimirov/actions/workflows/ci.yml/badge.svg)](https://github.com/non/antimirov/actions/workflows/ci.yml)
 [![codecov.io](http://codecov.io/github/non/antimirov/coverage.svg?branch=master)](http://codecov.io/github/non/antimirov?branch=master)
 
 ## Antimirov
diff --git a/build.sbt b/build.sbt
index 001bcb7..0060b3a 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,5 +1,6 @@
 import ReleaseTransformations._
 import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
+import org.scalajs.jsenv.nodejs.NodeJSEnv
 
 def ScalaCheck = Def.setting("org.scalacheck" %%% "scalacheck" % "1.14.3")
 def ScalaProps = Def.setting("com.github.scalaprops" %%% "scalaprops" % "0.8.0")
@@ -103,7 +104,7 @@ lazy val core = crossProject(JSPlatform, JVMPlatform)
     Global / scalaJSStage := FastOptStage,
     parallelExecution := false,
     coverageEnabled := false,
-    jsEnv := new org.scalajs.jsenv.nodejs.NodeJSEnv())
+    jsEnv := new NodeJSEnv(NodeJSEnv.Config().withArgs(List("--dns-result-order=ipv4first"))))
 
 lazy val coreJVM = core.jvm
 lazy val coreJS = core.js
@@ -120,7 +121,7 @@ lazy val check = crossProject(JSPlatform, JVMPlatform)
     Global / scalaJSStage := FastOptStage,
     parallelExecution := false,
     coverageEnabled := false,
-    jsEnv := new org.scalajs.jsenv.nodejs.NodeJSEnv())
+    jsEnv := new NodeJSEnv(NodeJSEnv.Config().withArgs(List("--dns-result-order=ipv4first"))))
 
 lazy val checkJVM = check.jvm
 lazy val checkJS = check.js
@@ -141,7 +142,7 @@ lazy val props = crossProject(JSPlatform, JVMPlatform)
   .jsSettings(
     Global / scalaJSStage := FastOptStage,
     coverageEnabled := false,
-    jsEnv := new org.scalajs.jsenv.nodejs.NodeJSEnv())
+    jsEnv := new NodeJSEnv(NodeJSEnv.Config().withArgs(List("--dns-result-order=ipv4first"))))
 
 lazy val propsJVM = props.jvm
 lazy val propsJS = props.js
@@ -159,7 +160,7 @@ lazy val tests = crossProject(JSPlatform, JVMPlatform)
     Global / scalaJSStage := FastOptStage,
     parallelExecution := false,
     coverageEnabled := false,
-    jsEnv := new org.scalajs.jsenv.nodejs.NodeJSEnv())
+    jsEnv := new NodeJSEnv(NodeJSEnv.Config().withArgs(List("--dns-result-order=ipv4first"))))
 
 lazy val testsJVM = tests.jvm
 lazy val testsJS = tests.js