Port many uses of (deprecated) ioutil package

NopCloser
ReadAll
ReadFile
WriteFile
TempFile
TempDir

ReadDir is not quite a find/replace, so will be addressed in a future CL.

Change-Id: Iec53d89d009779dd6259dd1113b8a4a8012496bb
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/757181
Auto-Submit: Kevin Lubick <kjlubick@google.com>
Commit-Queue: Joe Gregorio <jcgregorio@google.com>
Reviewed-by: Joe Gregorio <jcgregorio@google.com>
diff --git a/am/go/alert-to-pubsub/main.go b/am/go/alert-to-pubsub/main.go
index 7ee8256..4bcaf45 100644
--- a/am/go/alert-to-pubsub/main.go
+++ b/am/go/alert-to-pubsub/main.go
@@ -5,7 +5,7 @@
 	"context"
 	"encoding/json"
 	"flag"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"time"
 
@@ -164,7 +164,7 @@
 func (s *Server) alertHandler(w http.ResponseWriter, r *http.Request) {
 	liveness.Reset()
 	var incomingAlerts []Alert
-	b, err := ioutil.ReadAll(r.Body)
+	b, err := io.ReadAll(r.Body)
 	if err != nil {
 		httputils.ReportError(w, err, "Failed to read JSON.", http.StatusInternalServerError)
 		return
diff --git a/am/go/alertclient/client_test.go b/am/go/alertclient/client_test.go
index cf2f03d..3efc45f 100644
--- a/am/go/alertclient/client_test.go
+++ b/am/go/alertclient/client_test.go
@@ -3,7 +3,7 @@
 import (
 	"bytes"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"testing"
 
@@ -19,7 +19,7 @@
 	mockResponse := http.Response{
 		Status:     "200 OK",
 		StatusCode: http.StatusOK,
-		Body:       ioutil.NopCloser(bytes.NewBufferString(INCIDENTS_RESPONSE)),
+		Body:       io.NopCloser(bytes.NewBufferString(INCIDENTS_RESPONSE)),
 	}
 	mc.On("Get", "http://alert-manager:9000/_/incidents").Return(&mockResponse, nil)
 
@@ -45,7 +45,7 @@
 	mockResponse := http.Response{
 		Status:     "200 OK",
 		StatusCode: http.StatusOK,
-		Body:       ioutil.NopCloser(bytes.NewBufferString(SILENCES_RESPONSE)),
+		Body:       io.NopCloser(bytes.NewBufferString(SILENCES_RESPONSE)),
 	}
 	mc.On("Get", "http://alert-manager:9000/_/silences").Return(&mockResponse, nil)
 
diff --git a/android_ingest/go/androidingest/main.go b/android_ingest/go/androidingest/main.go
index 83543bd..59371b5 100644
--- a/android_ingest/go/androidingest/main.go
+++ b/android_ingest/go/androidingest/main.go
@@ -6,7 +6,7 @@
 	"flag"
 	"fmt"
 	"html/template"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/url"
 	"os"
@@ -162,7 +162,7 @@
 	uploads.Inc(1)
 
 	// Parse incoming JSON.
-	b, err := ioutil.ReadAll(r.Body)
+	b, err := io.ReadAll(r.Body)
 	if err != nil {
 		badRequest(w, r, err, "Failed to read body.")
 		recentRequests.AddBad(b, "Failed to read body")
diff --git a/android_ingest/go/parser/parser.go b/android_ingest/go/parser/parser.go
index 2ba5be7..764a4be 100644
--- a/android_ingest/go/parser/parser.go
+++ b/android_ingest/go/parser/parser.go
@@ -8,7 +8,6 @@
 	"errors"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"strconv"
 	"strings"
 
@@ -71,7 +70,7 @@
 // Convert the serialize *Incoming JSON into a JSON serialized format that Perf
 // supports. Also return the global keys and the buildID from the parsed file.
 func (c *Converter) Convert(incoming io.Reader, txLogName string) (map[string]string, string, []byte, error) {
-	b, err := ioutil.ReadAll(incoming)
+	b, err := io.ReadAll(incoming)
 	if err != nil {
 		return nil, "", nil, skerr.Wrapf(err, "Failed to read during convert %q", txLogName)
 	}
diff --git a/android_ingest/go/poprepo/poprepo.go b/android_ingest/go/poprepo/poprepo.go
index 2465035..a530ac2 100644
--- a/android_ingest/go/poprepo/poprepo.go
+++ b/android_ingest/go/poprepo/poprepo.go
@@ -8,8 +8,8 @@
 	"bytes"
 	"context"
 	"fmt"
-	"io/ioutil"
 	"net/url"
+	"os"
 	"path/filepath"
 	"strconv"
 	"strings"
@@ -66,7 +66,7 @@
 // The timestamp is seconds since the Unix epoch.
 func (p *PopRepo) GetLast(ctx context.Context) (int64, int64, string, error) {
 	fullpath := filepath.Join(p.checkout.Dir(), BUILDID_FILENAME)
-	b, err := ioutil.ReadFile(fullpath)
+	b, err := os.ReadFile(fullpath)
 	if err != nil {
 		return 0, 0, "", fmt.Errorf("Unable to read file %q: %s", fullpath, err)
 	}
@@ -144,7 +144,7 @@
 	if buildid <= lastBuildID {
 		return fmt.Errorf("Error: buildid=%d <= lastBuildID=%d, buildid added in wrong order.", buildid, lastBuildID)
 	}
-	if err := ioutil.WriteFile(filepath.Join(p.checkout.Dir(), BUILDID_FILENAME), []byte(fmt.Sprintf("%d %d", buildid, ts)), 0644); err != nil {
+	if err := os.WriteFile(filepath.Join(p.checkout.Dir(), BUILDID_FILENAME), []byte(fmt.Sprintf("%d %d", buildid, ts)), 0644); err != nil {
 		rollback = true
 		return fmt.Errorf("Failed to write updated buildid: %s", err)
 	}
diff --git a/android_ingest/go/poprepo/poprepo_test.go b/android_ingest/go/poprepo/poprepo_test.go
index fc2f269..1e3e655 100644
--- a/android_ingest/go/poprepo/poprepo_test.go
+++ b/android_ingest/go/poprepo/poprepo_test.go
@@ -2,7 +2,6 @@
 
 import (
 	"context"
-	"io/ioutil"
 	"os"
 	"strings"
 	"testing"
@@ -30,7 +29,7 @@
 	gb.CheckoutBranch(ctx, "somebranch")
 
 	// Create tmp dir that gets cleaned up.
-	workdir, err := ioutil.TempDir("", "poprepo")
+	workdir, err := os.MkdirTemp("", "poprepo")
 	assert.NoError(t, err)
 	defer func() {
 		_ = os.RemoveAll(workdir)
diff --git a/autoroll/go/autoroll-be/main.go b/autoroll/go/autoroll-be/main.go
index 582ed6f..1c2da66 100644
--- a/autoroll/go/autoroll-be/main.go
+++ b/autoroll/go/autoroll-be/main.go
@@ -6,7 +6,6 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"os/user"
 	"path/filepath"
@@ -123,7 +122,7 @@
 		configBytes, err = base64.StdEncoding.DecodeString(*configContents)
 	} else {
 		err = util.WithReadFile(*configFile, func(f io.Reader) error {
-			configBytes, err = ioutil.ReadAll(f)
+			configBytes, err = io.ReadAll(f)
 			return err
 		})
 	}
@@ -277,7 +276,7 @@
 		var gToken string
 		if *local {
 			pathToGithubToken := filepath.Join(user.HomeDir, github.GITHUB_TOKEN_FILENAME)
-			gBody, err := ioutil.ReadFile(pathToGithubToken)
+			gBody, err := os.ReadFile(pathToGithubToken)
 			if err != nil {
 				sklog.Fatalf("Couldn't find githubToken in %s: %s.", pathToGithubToken, err)
 			}
@@ -301,7 +300,7 @@
 				if _, err := fileutil.EnsureDirExists(sshKeyDestDir); err != nil {
 					sklog.Fatalf("Could not create %s: %s", sshKeyDest, err)
 				}
-				if err := ioutil.WriteFile(sshKeyDest, []byte(sshKey), 0600); err != nil {
+				if err := os.WriteFile(sshKeyDest, []byte(sshKey), 0600); err != nil {
 					sklog.Fatalf("Could not write to %s: %s", sshKeyDest, err)
 				}
 			}
diff --git a/autoroll/go/autoroll-config-generator/main.go b/autoroll/go/autoroll-config-generator/main.go
index 01ec852..458099c 100644
--- a/autoroll/go/autoroll-config-generator/main.go
+++ b/autoroll/go/autoroll-config-generator/main.go
@@ -7,7 +7,6 @@
 	"fmt"
 	"io"
 	"io/fs"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"path/filepath"
@@ -152,7 +151,7 @@
 			if err := os.MkdirAll(dir, os.ModePerm); err != nil {
 				return skerr.Wrapf(err, "failed to create dir %s", dir)
 			}
-			if err := ioutil.WriteFile(path, cfgBytes, os.ModePerm); err != nil {
+			if err := os.WriteFile(path, cfgBytes, os.ModePerm); err != nil {
 				return skerr.Wrapf(err, "failed to write %s", path)
 			}
 		}
@@ -186,7 +185,7 @@
 // processTemplate converts a single template into at least one config.
 func processTemplate(srcPath string, vars *templateVars) (map[string][]byte, error) {
 	// Read and execute the template.
-	tmplContents, err := ioutil.ReadFile(srcPath)
+	tmplContents, err := os.ReadFile(srcPath)
 	if err != nil {
 		return nil, skerr.Wrapf(err, "failed to read template file %s", srcPath)
 	}
diff --git a/autoroll/go/autoroll-config-generator/main_test.go b/autoroll/go/autoroll-config-generator/main_test.go
index a6e6b6d..7c14e21 100644
--- a/autoroll/go/autoroll-config-generator/main_test.go
+++ b/autoroll/go/autoroll-config-generator/main_test.go
@@ -2,7 +2,6 @@
 
 import (
 	"bytes"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -116,13 +115,13 @@
 	vars := &templateVars{
 		Vars: config_vars.FakeVars(),
 	}
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 	dir := filepath.Join(tmp, "templates")
 	require.NoError(t, os.MkdirAll(dir, os.ModePerm))
 	file := filepath.Join(dir, "my-template.tmpl")
-	require.NoError(t, ioutil.WriteFile(file, []byte(fakeTmplContents), os.ModePerm))
+	require.NoError(t, os.WriteFile(file, []byte(fakeTmplContents), os.ModePerm))
 	generatedDir := filepath.Join(tmp, "generated")
 
 	actual, err := processTemplate(file, vars)
diff --git a/autoroll/go/autoroll-config-presubmit/main.go b/autoroll/go/autoroll-config-presubmit/main.go
index f2a5209..13d382c 100644
--- a/autoroll/go/autoroll-config-presubmit/main.go
+++ b/autoroll/go/autoroll-config-presubmit/main.go
@@ -16,7 +16,6 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -111,7 +110,7 @@
 }
 
 func checkK8sConfigGeneration(ctx context.Context) bool {
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	if err != nil {
 		logf(ctx, "Failed to create tmp dir: %s", err)
 		return false
diff --git a/autoroll/go/codereview/roll_test.go b/autoroll/go/codereview/roll_test.go
index 98b1d1a..93b919a 100644
--- a/autoroll/go/codereview/roll_test.go
+++ b/autoroll/go/codereview/roll_test.go
@@ -3,8 +3,8 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"net/http"
+	"os"
 	"testing"
 	"time"
 
@@ -85,7 +85,7 @@
 func testGerritRoll(t *testing.T, cfg *config.GerritConfig) {
 	t.Skip("skbug.com/12357")
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
diff --git a/autoroll/go/commit_msg/cmd/mock-commit-msg/main.go b/autoroll/go/commit_msg/cmd/mock-commit-msg/main.go
index 0008454..09a8e6d 100644
--- a/autoroll/go/commit_msg/cmd/mock-commit-msg/main.go
+++ b/autoroll/go/commit_msg/cmd/mock-commit-msg/main.go
@@ -4,8 +4,8 @@
 	"context"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"log"
+	"os"
 	"os/user"
 	"path/filepath"
 	"strings"
@@ -63,7 +63,7 @@
 	client := httputils.DefaultClientConfig().WithTokenSource(ts).With2xxOnly().Client()
 
 	// Read the roller config file.
-	cfgBytes, err := ioutil.ReadFile(*configFile)
+	cfgBytes, err := os.ReadFile(*configFile)
 	if err != nil {
 		log.Fatalf("Failed to read %s: %s", *configFile, err)
 	}
@@ -87,7 +87,7 @@
 	if *compare {
 		// Create the working directory.
 		if *workdir == "" {
-			wd, err := ioutil.TempDir("", "")
+			wd, err := os.MkdirTemp("", "")
 			if err != nil {
 				log.Fatal(err)
 			}
@@ -127,7 +127,7 @@
 			}
 			pathToGithubToken := filepath.Join(user.HomeDir, github.GITHUB_TOKEN_FILENAME)
 			// Instantiate githubClient using the github token secret.
-			gBody, err := ioutil.ReadFile(pathToGithubToken)
+			gBody, err := os.ReadFile(pathToGithubToken)
 			if err != nil {
 				log.Fatalf("Couldn't find githubToken in %s: %s.", pathToGithubToken, err)
 			}
diff --git a/autoroll/go/repo_manager/android_repo_manager.go b/autoroll/go/repo_manager/android_repo_manager.go
index 2fe6520..a75aed3 100644
--- a/autoroll/go/repo_manager/android_repo_manager.go
+++ b/autoroll/go/repo_manager/android_repo_manager.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"os/user"
@@ -502,7 +501,7 @@
 `, r.projectMetadataFileConfig.Name, r.projectMetadataFileConfig.Description, r.projectMetadataFileConfig.HomePage, r.projectMetadataFileConfig.GitUrl, to.Id, r.projectMetadataFileConfig.LicenseType, d.Year(), d.Month(), d.Day())
 
 		metadataFilePath := filepath.Join(r.workdir, r.projectMetadataFileConfig.FilePath)
-		if err := ioutil.WriteFile(metadataFilePath, []byte(metadataContents), os.ModePerm); err != nil {
+		if err := os.WriteFile(metadataFilePath, []byte(metadataContents), os.ModePerm); err != nil {
 			return 0, fmt.Errorf("Error when writing to %s: %s", metadataFilePath, err)
 		}
 		if _, addGifErr := r.childRepo.Git(ctx, "add", metadataFilePath); addGifErr != nil {
diff --git a/autoroll/go/repo_manager/android_repo_manager_test.go b/autoroll/go/repo_manager/android_repo_manager_test.go
index 7034943..3d4c7ae 100644
--- a/autoroll/go/repo_manager/android_repo_manager_test.go
+++ b/autoroll/go/repo_manager/android_repo_manager_test.go
@@ -3,8 +3,8 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"net/http"
+	"os"
 	"strings"
 	"testing"
 
@@ -67,7 +67,7 @@
 }
 
 func setupAndroid(t *testing.T) (context.Context, *config_vars.Registry, string, func()) {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	// We do not actually want to shell out to git, as that would require having an actual
 	// git checkout. Instead, we intercept the calls to all binaries...
diff --git a/autoroll/go/repo_manager/child/revision_filter/valid_revision_from_http.go b/autoroll/go/repo_manager/child/revision_filter/valid_revision_from_http.go
index 917b670..e931199 100644
--- a/autoroll/go/repo_manager/child/revision_filter/valid_revision_from_http.go
+++ b/autoroll/go/repo_manager/child/revision_filter/valid_revision_from_http.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"regexp"
 	"strings"
@@ -55,7 +55,7 @@
 			if err != nil {
 				return nil, skerr.Wrapf(err, "failed to execute HTTP request")
 			}
-			b, err := ioutil.ReadAll(resp.Body)
+			b, err := io.ReadAll(resp.Body)
 			if err != nil {
 				return nil, skerr.Wrapf(err, "failed to read response body")
 			}
diff --git a/autoroll/go/repo_manager/command_repo_manager_test.go b/autoroll/go/repo_manager/command_repo_manager_test.go
index 5855671..9d87b09 100644
--- a/autoroll/go/repo_manager/command_repo_manager_test.go
+++ b/autoroll/go/repo_manager/command_repo_manager_test.go
@@ -6,7 +6,7 @@
 import (
 	"context"
 	"encoding/json"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 	"testing"
@@ -59,7 +59,7 @@
 	// Setup.
 	// We do actually want to call git for some commands, so we need to use the git from CIPD.
 	ctx := cipd_git.UseGitFinder(context.Background())
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 	urlmock := mockhttpclient.NewURLMock()
diff --git a/autoroll/go/repo_manager/copy_repo_manager_test.go b/autoroll/go/repo_manager/copy_repo_manager_test.go
index 9cced7f..9bdcb39 100644
--- a/autoroll/go/repo_manager/copy_repo_manager_test.go
+++ b/autoroll/go/repo_manager/copy_repo_manager_test.go
@@ -4,8 +4,8 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net/url"
+	"os"
 	"path"
 	"path/filepath"
 	"strings"
@@ -70,7 +70,7 @@
 }
 
 func setupCopy(t *testing.T) (context.Context, *config.ParentChildRepoManagerConfig, string, *parentChildRepoManager, *git_testutils.GitBuilder, *git_testutils.GitBuilder, *gitiles_testutils.MockRepo, *gitiles_testutils.MockRepo, []string, *mockhttpclient.URLMock, func()) {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	// Create child and parent repos.
diff --git a/autoroll/go/repo_manager/deps_repo_manager_test.go b/autoroll/go/repo_manager/deps_repo_manager_test.go
index fdb8c56..2a9bf94 100644
--- a/autoroll/go/repo_manager/deps_repo_manager_test.go
+++ b/autoroll/go/repo_manager/deps_repo_manager_test.go
@@ -4,8 +4,8 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net/http"
+	"os"
 	"path"
 	"path/filepath"
 	"strings"
@@ -86,7 +86,7 @@
 }
 
 func setupDEPSRepoManager(t *testing.T, cfg *config.ParentChildRepoManagerConfig) (context.Context, *parentChildRepoManager, string, *git_testutils.GitBuilder, []string, *git_testutils.GitBuilder, *exec.CommandCollector, *vcsinfo.LongCommit, *mockhttpclient.URLMock, *bool, func()) {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	// Create child and parent repos.
diff --git a/autoroll/go/repo_manager/freetype_repo_manager_test.go b/autoroll/go/repo_manager/freetype_repo_manager_test.go
index 1a91620..0191794 100644
--- a/autoroll/go/repo_manager/freetype_repo_manager_test.go
+++ b/autoroll/go/repo_manager/freetype_repo_manager_test.go
@@ -4,8 +4,8 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net/url"
+	"os"
 	"path"
 	"strings"
 	"testing"
@@ -42,7 +42,7 @@
 
 func setupFreeType(t *testing.T) (context.Context, string, RepoManager, *git_testutils.GitBuilder, *git_testutils.GitBuilder, *gitiles_testutils.MockRepo, *gitiles_testutils.MockRepo, []string, *mockhttpclient.URLMock, func()) {
 
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	ctx := cipd_git.UseGitFinder(context.Background())
diff --git a/autoroll/go/repo_manager/fuchsia_sdk_android_repo_manager_test.go b/autoroll/go/repo_manager/fuchsia_sdk_android_repo_manager_test.go
index 3810df9..68768a9 100644
--- a/autoroll/go/repo_manager/fuchsia_sdk_android_repo_manager_test.go
+++ b/autoroll/go/repo_manager/fuchsia_sdk_android_repo_manager_test.go
@@ -4,7 +4,7 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 	"testing"
@@ -52,7 +52,7 @@
 }
 
 func setupFuchsiaSDKAndroid(t *testing.T) (context.Context, *parentChildRepoManager, *mockhttpclient.URLMock, *gitiles_testutils.MockRepo, *git_testutils.GitBuilder, string, func()) {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	cfg := fuchsiaAndroidCfg(t)
diff --git a/autoroll/go/repo_manager/fuchsia_sdk_repo_manager_test.go b/autoroll/go/repo_manager/fuchsia_sdk_repo_manager_test.go
index 869ce69..1863a6c 100644
--- a/autoroll/go/repo_manager/fuchsia_sdk_repo_manager_test.go
+++ b/autoroll/go/repo_manager/fuchsia_sdk_repo_manager_test.go
@@ -4,8 +4,8 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net/url"
+	"os"
 	"strings"
 	"testing"
 
@@ -86,7 +86,7 @@
 }
 
 func setupFuchsiaSDK(t *testing.T) (context.Context, *parentChildRepoManager, *mockhttpclient.URLMock, *gitiles_testutils.MockRepo, *git_testutils.GitBuilder, func()) {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	ctx := cipd_git.UseGitFinder(context.Background())
diff --git a/autoroll/go/repo_manager/github_cipd_deps_repo_manager_test.go b/autoroll/go/repo_manager/github_cipd_deps_repo_manager_test.go
index d2ecfa5..cbc5d95 100644
--- a/autoroll/go/repo_manager/github_cipd_deps_repo_manager_test.go
+++ b/autoroll/go/repo_manager/github_cipd_deps_repo_manager_test.go
@@ -4,7 +4,6 @@
 	"context"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"path/filepath"
@@ -88,7 +87,7 @@
 }
 
 func setupGithubCipdDEPS(t *testing.T, cfg *config.ParentChildRepoManagerConfig) (context.Context, *parentChildRepoManager, string, *git_testutils.GitBuilder, *exec.CommandCollector, *mocks.CIPDClient, *mockhttpclient.URLMock, func()) {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	ctx := cipd_git.UseGitFinder(context.Background())
 
diff --git a/autoroll/go/repo_manager/github_deps_repo_manager_test.go b/autoroll/go/repo_manager/github_deps_repo_manager_test.go
index 8530d48..6ccb385 100644
--- a/autoroll/go/repo_manager/github_deps_repo_manager_test.go
+++ b/autoroll/go/repo_manager/github_deps_repo_manager_test.go
@@ -5,8 +5,8 @@
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"net/http"
+	"os"
 	"path/filepath"
 	"strings"
 	"testing"
@@ -81,7 +81,7 @@
 }
 
 func setupGithubDEPS(t *testing.T, c *config.ParentChildRepoManagerConfig) (context.Context, *parentChildRepoManager, string, *git_testutils.GitBuilder, []string, *git_testutils.GitBuilder, *exec.CommandCollector, *mockhttpclient.URLMock, func()) {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	ctx := cipd_git.UseGitFinder(context.Background())
 
diff --git a/autoroll/go/repo_manager/github_repo_manager_test.go b/autoroll/go/repo_manager/github_repo_manager_test.go
index 68459c6..d6883f6 100644
--- a/autoroll/go/repo_manager/github_repo_manager_test.go
+++ b/autoroll/go/repo_manager/github_repo_manager_test.go
@@ -5,7 +5,6 @@
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"path/filepath"
@@ -78,7 +77,7 @@
 }
 
 func setupGithub(t *testing.T, cfg *config.ParentChildRepoManagerConfig) (context.Context, *parentChildRepoManager, string, *git_testutils.GitBuilder, []string, *git_testutils.GitBuilder, *exec.CommandCollector, *mockhttpclient.URLMock, func()) {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	ctx := context.Background()
 
diff --git a/autoroll/go/repo_manager/no_checkout_deps_repo_manager_test.go b/autoroll/go/repo_manager/no_checkout_deps_repo_manager_test.go
index c7b4822..4e6f6cf 100644
--- a/autoroll/go/repo_manager/no_checkout_deps_repo_manager_test.go
+++ b/autoroll/go/repo_manager/no_checkout_deps_repo_manager_test.go
@@ -4,7 +4,7 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 	"testing"
@@ -26,7 +26,7 @@
 
 func setupNoCheckout(t *testing.T, cfg *config.ParentChildRepoManagerConfig) (context.Context, string, *parentChildRepoManager, *git_testutils.GitBuilder, *git_testutils.GitBuilder, *gitiles_testutils.MockRepo, *gitiles_testutils.MockRepo, []string, *mockhttpclient.URLMock, func()) {
 
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	// Create child and parent repos.
diff --git a/autoroll/go/repo_manager/parent/freetype.go b/autoroll/go/repo_manager/parent/freetype.go
index 5515357..ca0fd4a 100644
--- a/autoroll/go/repo_manager/parent/freetype.go
+++ b/autoroll/go/repo_manager/parent/freetype.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"path"
@@ -119,7 +118,7 @@
 // Perform a three-way merge for this header file in a temporary dir. Adds the
 // new contents to the changes map.
 func mergeInclude(ctx context.Context, include, from, to string, fs vfs.FS, changes map[string]string, parentRepo *gitiles_common.GitilesRepo, localChildRepo *git.Repo) error {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	if err != nil {
 		return skerr.Wrap(err)
 	}
@@ -146,7 +145,7 @@
 	if err := os.MkdirAll(dir, os.ModePerm); err != nil {
 		return skerr.Wrap(err)
 	}
-	if err := ioutil.WriteFile(dest, oldParentBytes, os.ModePerm); err != nil {
+	if err := os.WriteFile(dest, oldParentBytes, os.ModePerm); err != nil {
 		return skerr.Wrap(err)
 	}
 	if _, err := gd.Git(ctx, "add", dest); err != nil {
@@ -163,7 +162,7 @@
 		return skerr.Wrap(err)
 	}
 	oldPath := filepath.Join(wd, "old")
-	if err := ioutil.WriteFile(oldPath, []byte(oldChildContents), os.ModePerm); err != nil {
+	if err := os.WriteFile(oldPath, []byte(oldChildContents), os.ModePerm); err != nil {
 		return skerr.Wrap(err)
 	}
 
@@ -173,7 +172,7 @@
 		return skerr.Wrap(err)
 	}
 	newPath := filepath.Join(wd, "new")
-	if err := ioutil.WriteFile(newPath, []byte(newChildContents), os.ModePerm); err != nil {
+	if err := os.WriteFile(newPath, []byte(newChildContents), os.ModePerm); err != nil {
 		return skerr.Wrap(err)
 	}
 
@@ -183,7 +182,7 @@
 	}
 
 	// Read the resulting contents.
-	newParentContents, err := ioutil.ReadFile(dest)
+	newParentContents, err := os.ReadFile(dest)
 	if err != nil {
 		return skerr.Wrap(err)
 	}
diff --git a/autoroll/go/repo_manager/parent/git_checkout.go b/autoroll/go/repo_manager/parent/git_checkout.go
index 4823e78..af3919f 100644
--- a/autoroll/go/repo_manager/parent/git_checkout.go
+++ b/autoroll/go/repo_manager/parent/git_checkout.go
@@ -6,7 +6,6 @@
 
 import (
 	"context"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -125,7 +124,7 @@
 	sklog.Infof("Writing to file \"%s\".", path)
 
 	fullPath := filepath.Join(co.Dir(), path)
-	if err := ioutil.WriteFile(fullPath, []byte(contents), os.ModePerm); err != nil {
+	if err := os.WriteFile(fullPath, []byte(contents), os.ModePerm); err != nil {
 		return skerr.Wrap(err)
 	}
 	if _, err := co.Git(ctx, "add", path); err != nil {
diff --git a/autoroll/go/repo_manager/parent/git_checkout_test.go b/autoroll/go/repo_manager/parent/git_checkout_test.go
index e9f522d..5df957b 100644
--- a/autoroll/go/repo_manager/parent/git_checkout_test.go
+++ b/autoroll/go/repo_manager/parent/git_checkout_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"testing"
 
 	"github.com/stretchr/testify/require"
@@ -39,7 +39,7 @@
 	ctx, gb := setup(t)
 	defer gb.Cleanup()
 
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmpDir)
 
@@ -64,7 +64,7 @@
 	ctx, gb := setup(t)
 	defer gb.Cleanup()
 
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmpDir)
 
diff --git a/autoroll/go/repo_manager/parent/go_mod.go b/autoroll/go/repo_manager/parent/go_mod.go
index 57cb252..cd2c82d 100644
--- a/autoroll/go/repo_manager/parent/go_mod.go
+++ b/autoroll/go/repo_manager/parent/go_mod.go
@@ -3,8 +3,8 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"net/http"
+	"os"
 	"path/filepath"
 	"regexp"
 	"strings"
@@ -131,7 +131,7 @@
 	// generalize this, we'd need a special type of Child which retrieves
 	// semantic version Git tags instead of individual commit hashes, and we'd
 	// have to distinguish between the two flows here.
-	b, err := ioutil.ReadFile(filepath.Join(p.Checkout.Dir(), goModFile))
+	b, err := os.ReadFile(filepath.Join(p.Checkout.Dir(), goModFile))
 	if err != nil {
 		return "", skerr.Wrapf(err, "failed to read %s", goModFile)
 	}
diff --git a/autoroll/go/repo_manager/parent/go_mod_test.go b/autoroll/go/repo_manager/parent/go_mod_test.go
index 6492d79..df8ac0f 100644
--- a/autoroll/go/repo_manager/parent/go_mod_test.go
+++ b/autoroll/go/repo_manager/parent/go_mod_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"os"
 	"testing"
 
 	"github.com/stretchr/testify/require"
@@ -60,7 +60,7 @@
 func setupGoModGerrit(t *testing.T) (context.Context, *goModParent, *gerrit_testutils.MockGerrit, func()) {
 	// We do actually want to call git for some commands, so we need to use the git from CIPD.
 	ctx := cipd_git.UseGitFinder(context.Background())
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	parent := git_testutils.GitInit(t, ctx)
diff --git a/autoroll/go/repo_manager/parent/pre_upload_steps.go b/autoroll/go/repo_manager/parent/pre_upload_steps.go
index de467ce..3c36663 100644
--- a/autoroll/go/repo_manager/parent/pre_upload_steps.go
+++ b/autoroll/go/repo_manager/parent/pre_upload_steps.go
@@ -7,7 +7,6 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"path"
@@ -357,7 +356,7 @@
 // ANGLERollChromium runs the ANGLE roll_chromium_deps.py script.
 func ANGLERollChromium(ctx context.Context, env []string, _ *http.Client, parentRepoDir string, from *revision.Revision, to *revision.Revision) error {
 	sklog.Info("Running roll_chromium_deps script...")
-	contents, err := ioutil.ReadFile(filepath.Join(parentRepoDir, deps_parser.DepsFileName))
+	contents, err := os.ReadFile(filepath.Join(parentRepoDir, deps_parser.DepsFileName))
 	if err != nil {
 		return skerr.Wrap(err)
 	}
diff --git a/autoroll/go/repo_manager/semver_gcs_repo_manager_test.go b/autoroll/go/repo_manager/semver_gcs_repo_manager_test.go
index f7e3862..a5b05ed 100644
--- a/autoroll/go/repo_manager/semver_gcs_repo_manager_test.go
+++ b/autoroll/go/repo_manager/semver_gcs_repo_manager_test.go
@@ -4,9 +4,9 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 	"net/url"
+	"os"
 	"path"
 	"strings"
 	"testing"
@@ -93,7 +93,7 @@
 }
 
 func setupAfdo(t *testing.T) (context.Context, *parentChildRepoManager, *mockhttpclient.URLMock, *gitiles_testutils.MockRepo, *git_testutils.GitBuilder, func()) {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	ctx := cipd_git.UseGitFinder(context.Background())
diff --git a/bazel/gazelle/frontend/language/language.go b/bazel/gazelle/frontend/language/language.go
index 6f92077..e968ac3 100644
--- a/bazel/gazelle/frontend/language/language.go
+++ b/bazel/gazelle/frontend/language/language.go
@@ -1,8 +1,8 @@
 package language
 
 import (
-	"io/ioutil"
 	"log"
+	"os"
 	"path"
 	"path/filepath"
 	"regexp"
@@ -546,7 +546,7 @@
 // extractImportsFromSassFile returns the verbatim paths of the import statements found in the given
 // Sass file.
 func extractImportsFromSassFile(path string) []string {
-	b, err := ioutil.ReadFile(path)
+	b, err := os.ReadFile(path)
 	if err != nil {
 		log.Panicf("Error reading file %q: %v", path, err)
 	}
@@ -556,7 +556,7 @@
 // extractImportsFromTypeScriptFile returns the verbatim paths of the import statements found in the
 // given TypeScript file.
 func extractImportsFromTypeScriptFile(path string) []string {
-	b, err := ioutil.ReadFile(path)
+	b, err := os.ReadFile(path)
 	if err != nil {
 		log.Panicf("Error reading file %q: %v", path, err)
 	}
diff --git a/bazel/gazelle/frontend/resolver/resolver.go b/bazel/gazelle/frontend/resolver/resolver.go
index 345f21a..4040fbc 100644
--- a/bazel/gazelle/frontend/resolver/resolver.go
+++ b/bazel/gazelle/frontend/resolver/resolver.go
@@ -2,8 +2,8 @@
 
 import (
 	"encoding/json"
-	"io/ioutil"
 	"log"
+	"os"
 	"path"
 	"path/filepath"
 	"sort"
@@ -487,7 +487,7 @@
 	}
 
 	// Read in and unmarshall package.json file.
-	b, err := ioutil.ReadFile(path)
+	b, err := os.ReadFile(path)
 	if err != nil {
 		log.Panicf("Error reading file %q: %v", path, err)
 	}
diff --git a/bazel/go/bazel/test/bazel_test.go b/bazel/go/bazel/test/bazel_test.go
index 134cac0..fc9762c 100644
--- a/bazel/go/bazel/test/bazel_test.go
+++ b/bazel/go/bazel/test/bazel_test.go
@@ -3,7 +3,7 @@
 package test
 
 import (
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 	"testing"
@@ -23,7 +23,7 @@
 	unittest.BazelOnlyTest(t)
 
 	runfile := filepath.Join(bazel.RunfilesDir(), "bazel/go/bazel/test/testdata/hello.txt")
-	bytes, err := ioutil.ReadFile(runfile)
+	bytes, err := os.ReadFile(runfile)
 	require.NoError(t, err)
 	require.Equal(t, "Hello, world!", strings.TrimSpace(string(bytes)))
 }
diff --git a/bazel/test_on_env/examples/env.go b/bazel/test_on_env/examples/env.go
index 05a4ced..52a682d 100644
--- a/bazel/test_on_env/examples/env.go
+++ b/bazel/test_on_env/examples/env.go
@@ -3,7 +3,6 @@
 
 import (
 	"fmt"
-	"io/ioutil"
 	"net"
 	"net/http"
 	"os"
@@ -56,13 +55,13 @@
 	port := listener.Addr().(*net.TCPAddr).Port
 
 	// Write port file first.
-	err = ioutil.WriteFile(envPortFile, []byte(strconv.Itoa(port)), 0644)
+	err = os.WriteFile(envPortFile, []byte(strconv.Itoa(port)), 0644)
 	if err != nil {
 		panic(err)
 	}
 
 	// Write ready file second. This signals that the environment is ready for the tests to execute.
-	err = ioutil.WriteFile(envReadyFile, []byte{}, 0644)
+	err = os.WriteFile(envReadyFile, []byte{}, 0644)
 	if err != nil {
 		panic(err)
 	}
diff --git a/bazel/test_on_env/examples/go/go_test.go b/bazel/test_on_env/examples/go/go_test.go
index 41ebf9c..09afe74 100644
--- a/bazel/test_on_env/examples/go/go_test.go
+++ b/bazel/test_on_env/examples/go/go_test.go
@@ -3,7 +3,7 @@
 
 import (
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"os"
 	"path"
@@ -19,7 +19,7 @@
 	if envDir == "" {
 		panic(fmt.Sprintf("required environment variable ENV_DIR is unset"))
 	}
-	portFileBytes, err := ioutil.ReadFile(path.Join(envDir, envPortFileBaseName))
+	portFileBytes, err := os.ReadFile(path.Join(envDir, envPortFileBaseName))
 	if err != nil {
 		panic(err)
 	}
@@ -70,7 +70,7 @@
 				t.Errorf("got status code: %d, want: %d", resp.StatusCode, tc.expectedStatusCode)
 			}
 			if tc.expectedBody != "" {
-				bodyBytes, err := ioutil.ReadAll(resp.Body)
+				bodyBytes, err := io.ReadAll(resp.Body)
 				if err != nil {
 					t.Errorf("error reading HTTP response body: %v", err)
 				}
diff --git a/bugs-central/go/bugs/github/github.go b/bugs-central/go/bugs/github/github.go
index 4860e05..fb33941 100644
--- a/bugs-central/go/bugs/github/github.go
+++ b/bugs-central/go/bugs/github/github.go
@@ -6,7 +6,7 @@
 	"context"
 	"errors"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"strconv"
 	"strings"
 	"time"
@@ -90,7 +90,7 @@
 
 // New returns an instance of the github implementation of bugs.BugFramework.
 func New(ctx context.Context, repoOwner, repoName, credPath string, openIssues *bugs.OpenIssues, queryConfig *GithubQueryConfig) (bugs.BugFramework, error) {
-	gBody, err := ioutil.ReadFile(credPath)
+	gBody, err := os.ReadFile(credPath)
 	if err != nil {
 		return nil, skerr.Wrapf(err, "could not find githubToken in %s", credPath)
 	}
diff --git a/cd/go/stages/stage_file.go b/cd/go/stages/stage_file.go
index 33b8c79..8afe186 100644
--- a/cd/go/stages/stage_file.go
+++ b/cd/go/stages/stage_file.go
@@ -4,7 +4,7 @@
 	"bytes"
 	"encoding/json"
 	"io"
-	"io/ioutil"
+	"os"
 
 	"go.skia.org/infra/go/skerr"
 	"go.skia.org/infra/go/util"
@@ -48,7 +48,7 @@
 
 // DecodeFile parses the given file as a StageFile.
 func DecodeFile(filepath string) (*StageFile, error) {
-	b, err := ioutil.ReadFile(filepath)
+	b, err := os.ReadFile(filepath)
 	if err != nil {
 		return nil, skerr.Wrap(err)
 	}
diff --git a/cherrypick-watcher/go/config/config_test.go b/cherrypick-watcher/go/config/config_test.go
index 6b60b70..5b9dc09 100644
--- a/cherrypick-watcher/go/config/config_test.go
+++ b/cherrypick-watcher/go/config/config_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"fmt"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"testing"
 
@@ -14,7 +14,7 @@
 func TestParseCfg(t *testing.T) {
 	dir := testutils.TestDataDir(t)
 	configFile := filepath.Join(dir, "test-config.json")
-	cfgContents, err := ioutil.ReadFile(configFile)
+	cfgContents, err := os.ReadFile(configFile)
 	require.Nil(t, err)
 
 	supportedBranchDeps, err := ParseCfg(cfgContents)
diff --git a/codereview-watcher/go/codereview-watcher/main.go b/codereview-watcher/go/codereview-watcher/main.go
index 50bef1d..78eafd2 100644
--- a/codereview-watcher/go/codereview-watcher/main.go
+++ b/codereview-watcher/go/codereview-watcher/main.go
@@ -8,7 +8,7 @@
 	"context"
 	"flag"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"os/user"
 	"path/filepath"
 	"strings"
@@ -252,7 +252,7 @@
 		}
 		pathToGithubToken = filepath.Join(usr.HomeDir, github.GITHUB_TOKEN_FILENAME)
 	}
-	gBody, err := ioutil.ReadFile(pathToGithubToken)
+	gBody, err := os.ReadFile(pathToGithubToken)
 	if err != nil {
 		sklog.Fatalf("Could not find githubToken in %s: %s", pathToGithubToken, err)
 	}
diff --git a/comments/go/extract_comments/main.go b/comments/go/extract_comments/main.go
index df5a392..2ff7e18 100644
--- a/comments/go/extract_comments/main.go
+++ b/comments/go/extract_comments/main.go
@@ -7,7 +7,6 @@
 	"encoding/json"
 	"flag"
 	"io"
-	"io/ioutil"
 	"net/url"
 	"os"
 	"path/filepath"
@@ -38,7 +37,7 @@
 	}
 	comments := []*extract.GM{}
 	for _, filename := range matches {
-		b, err := ioutil.ReadFile(filename)
+		b, err := os.ReadFile(filename)
 		if err != nil {
 			sklog.Warningf("Failed to read file %s: %s", filename, err)
 		}
diff --git a/comp-ui/go/compui/compui.go b/comp-ui/go/compui/compui.go
index 908cb81..78b9c75 100644
--- a/comp-ui/go/compui/compui.go
+++ b/comp-ui/go/compui/compui.go
@@ -27,7 +27,6 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -470,7 +469,7 @@
 func readBenchMarksFromFile(ctx context.Context, filename string) (map[string]*Benchmark, error) {
 	sklog.Infof("Reading configs from %q", filename)
 	benchmarks := map[string]*Benchmark{}
-	b, err := ioutil.ReadFile(filename)
+	b, err := os.ReadFile(filename)
 	if err != nil {
 		return nil, skerr.Wrapf(err, "Failed to read file.")
 	}
diff --git a/comp-ui/go/compui/compui_test.go b/comp-ui/go/compui/compui_test.go
index c2f65d3..e068aa3 100644
--- a/comp-ui/go/compui/compui_test.go
+++ b/comp-ui/go/compui/compui_test.go
@@ -4,7 +4,6 @@
 	"bytes"
 	"context"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"path/filepath"
@@ -280,7 +279,7 @@
 
 func TestReadBenchmarksFromFile_ReadCanaryJSON_ReturnsParsedFile(t *testing.T) {
 	filename := filepath.Join(t.TempDir(), "file.json")
-	err := ioutil.WriteFile(filename, []byte(TestFileContents), 0644)
+	err := os.WriteFile(filename, []byte(TestFileContents), 0644)
 	require.NoError(t, err)
 	benchmarks, err := readBenchMarksFromFile(context.Background(), filename)
 	require.NoError(t, err)
diff --git a/comp-ui/go/compui/download/download.go b/comp-ui/go/compui/download/download.go
index 540d09b..8541ab0 100644
--- a/comp-ui/go/compui/download/download.go
+++ b/comp-ui/go/compui/download/download.go
@@ -4,7 +4,7 @@
 	"archive/zip"
 	"bytes"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"os"
 	"path/filepath"
@@ -86,7 +86,7 @@
 		return "", err
 	}
 	defer util.Close(rc)
-	unzippedBody, err := ioutil.ReadAll(rc)
+	unzippedBody, err := io.ReadAll(rc)
 	if err != nil {
 		return "", err
 	}
diff --git a/comp-ui/go/compui/urls/urls.go b/comp-ui/go/compui/urls/urls.go
index 16bffbc..fa5189e 100644
--- a/comp-ui/go/compui/urls/urls.go
+++ b/comp-ui/go/compui/urls/urls.go
@@ -2,7 +2,7 @@
 
 import (
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"strings"
 
@@ -91,5 +91,5 @@
 	if resp.StatusCode != http.StatusOK {
 		return nil, fmt.Errorf("Failed to load: %s", resp.Status)
 	}
-	return ioutil.ReadAll(resp.Body)
+	return io.ReadAll(resp.Body)
 }
diff --git a/ct/go/master_scripts/metrics_analysis_on_workers/main.go b/ct/go/master_scripts/metrics_analysis_on_workers/main.go
index 267e5f9..e0e0036 100644
--- a/ct/go/master_scripts/metrics_analysis_on_workers/main.go
+++ b/ct/go/master_scripts/metrics_analysis_on_workers/main.go
@@ -12,7 +12,6 @@
 	"errors"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -90,7 +89,7 @@
 		// missing newlines.
 		patch = patch + "\n"
 		patchPath := filepath.Join(os.TempDir(), *runID+fileSuffix)
-		if err := ioutil.WriteFile(patchPath, []byte(patch), 0666); err != nil {
+		if err := os.WriteFile(patchPath, []byte(patch), 0666); err != nil {
 			return fmt.Errorf("Could not write patch %s to %s: %s", patch, patchPath, err)
 		}
 		defer skutil.Remove(patchPath)
@@ -218,7 +217,7 @@
 	if len(traceURLs) == 0 {
 		return fmt.Errorf("There were no traceURLs found for the analysis output link: %s", *analysisOutputLink)
 	}
-	if err := ioutil.WriteFile(outputPath, []byte(strings.Join(traceURLs, ",")), 0644); err != nil {
+	if err := os.WriteFile(outputPath, []byte(strings.Join(traceURLs, ",")), 0644); err != nil {
 		return fmt.Errorf("Could not write traceURLs to %s: %s", outputPath, err)
 	}
 	return nil
diff --git a/ct/go/master_scripts/run_chromium_analysis_on_workers/main.go b/ct/go/master_scripts/run_chromium_analysis_on_workers/main.go
index a482025..6c41ec6 100644
--- a/ct/go/master_scripts/run_chromium_analysis_on_workers/main.go
+++ b/ct/go/master_scripts/run_chromium_analysis_on_workers/main.go
@@ -8,7 +8,6 @@
 	"errors"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -122,7 +121,7 @@
 		// missing newlines.
 		patch = patch + "\n"
 		patchPath := filepath.Join(os.TempDir(), *runID+fileSuffix)
-		if err := ioutil.WriteFile(patchPath, []byte(patch), 0666); err != nil {
+		if err := os.WriteFile(patchPath, []byte(patch), 0666); err != nil {
 			return fmt.Errorf("Could not write patch %s to %s: %s", patch, patchPath, err)
 		}
 		defer skutil.Remove(patchPath)
diff --git a/ct/go/master_scripts/run_chromium_perf_on_workers/main.go b/ct/go/master_scripts/run_chromium_perf_on_workers/main.go
index 91a011f0..a53de4a 100644
--- a/ct/go/master_scripts/run_chromium_perf_on_workers/main.go
+++ b/ct/go/master_scripts/run_chromium_perf_on_workers/main.go
@@ -8,7 +8,6 @@
 	"errors"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strconv"
@@ -136,7 +135,7 @@
 		// missing newlines.
 		patch = patch + "\n"
 		patchPath := filepath.Join(os.TempDir(), *runID+fileSuffix)
-		if err := ioutil.WriteFile(patchPath, []byte(patch), 0666); err != nil {
+		if err := os.WriteFile(patchPath, []byte(patch), 0666); err != nil {
 			return fmt.Errorf("Could not write patch %s to %s: %s", patch, patchPath, err)
 		}
 		defer skutil.Remove(patchPath)
diff --git a/ct/go/util/ct_perf.go b/ct/go/util/ct_perf.go
index 89b64d4..b5726bd 100644
--- a/ct/go/util/ct_perf.go
+++ b/ct/go/util/ct_perf.go
@@ -8,7 +8,6 @@
 	"encoding/json"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -87,7 +86,7 @@
 	defer util.RemoveAll(workdir)
 
 	// Step 1: Add a commit to CT Perf's synthetic repo in CT_PERF_REPO
-	tmpDir, err := ioutil.TempDir(workdir, uniqueID)
+	tmpDir, err := os.MkdirTemp(workdir, uniqueID)
 	if err != nil {
 		return skerr.Fmt("Could not create tmpDir in %s: %s", workdir, err)
 	}
@@ -113,7 +112,7 @@
 		return skerr.Fmt("Could not convert %v to JSON: %s", ctPerfData, err)
 	}
 	jsonFile := path.Join(workdir, fmt.Sprintf("%s.json", uniqueID))
-	if err := ioutil.WriteFile(jsonFile, perfJson, 0644); err != nil {
+	if err := os.WriteFile(jsonFile, perfJson, 0644); err != nil {
 		return skerr.Fmt("Could not write to %s: %s", jsonFile, err)
 	}
 
@@ -132,7 +131,7 @@
 // it into the specified repo. Returns the full hash of the commit.
 func commitToSyntheticRepo(ctx context.Context, groupName, uniqueID, gitExec string, checkout *git.Checkout) (string, error) {
 	// Create a new file using the uniqueID and commit it to the synthetic repo.
-	if err := ioutil.WriteFile(filepath.Join(checkout.Dir(), uniqueID), []byte(uniqueID), 0644); err != nil {
+	if err := os.WriteFile(filepath.Join(checkout.Dir(), uniqueID), []byte(uniqueID), 0644); err != nil {
 		return "", skerr.Fmt("Failed to write %s: %s", uniqueID, err)
 	}
 	if msg, err := checkout.Git(ctx, "add", uniqueID); err != nil {
diff --git a/ct/go/util/ct_perf_test.go b/ct/go/util/ct_perf_test.go
index 864ef4e..5ab6f94 100644
--- a/ct/go/util/ct_perf_test.go
+++ b/ct/go/util/ct_perf_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 	"testing"
@@ -39,7 +39,7 @@
 	gb.CheckoutBranch(ctx, "somebranch")
 
 	// Create tmp dir that gets cleaned up.
-	workdir, err := ioutil.TempDir("", "ct_perf_test_commit")
+	workdir, err := os.MkdirTemp("", "ct_perf_test_commit")
 	require.NoError(t, err)
 	defer util.RemoveAll(workdir)
 
diff --git a/ct/go/util/gs_test.go b/ct/go/util/gs_test.go
index 2a61389..ddb66a1 100644
--- a/ct/go/util/gs_test.go
+++ b/ct/go/util/gs_test.go
@@ -2,6 +2,7 @@
 
 import (
 	"io/ioutil"
+	"os"
 	"path/filepath"
 	"testing"
 
@@ -17,7 +18,7 @@
 	gs, err := NewGcsUtil(nil)
 	assert.NoError(t, err)
 
-	localDir, err := ioutil.TempDir("", "util_test_")
+	localDir, err := os.MkdirTemp("", "util_test_")
 	assert.NoError(t, err)
 	defer util.RemoveAll(localDir)
 	pageSetToIndex, err := gs.DownloadSwarmingArtifacts(localDir, testPagesetsDirName, "10k", 1, 2)
diff --git a/ct/go/util/util.go b/ct/go/util/util.go
index 4d2c608..4901c68 100644
--- a/ct/go/util/util.go
+++ b/ct/go/util/util.go
@@ -1071,7 +1071,7 @@
 	}
 
 	// Download CAS output of the task.
-	outputDir, err := ioutil.TempDir("", fmt.Sprintf("download_%s", resp.TaskId))
+	outputDir, err := os.MkdirTemp("", fmt.Sprintf("download_%s", resp.TaskId))
 	if err != nil {
 		return "", fmt.Errorf("Failed to create temporary dir: %s", err)
 	}
@@ -1080,7 +1080,7 @@
 		return "", fmt.Errorf("Could not download %s: %s", outputDigest, err)
 	}
 	outputFile := filepath.Join(outputDir, ISOLATE_TELEMETRY_FILENAME)
-	contents, err := ioutil.ReadFile(outputFile)
+	contents, err := os.ReadFile(outputFile)
 	if err != nil {
 		return "", fmt.Errorf("Could not read outputfile %s: %s", outputFile, err)
 	}
@@ -1245,7 +1245,7 @@
 	}
 
 	// Download output of the task.
-	outputDir, err := ioutil.TempDir("", fmt.Sprintf("download_%s", resp.TaskId))
+	outputDir, err := os.MkdirTemp("", fmt.Sprintf("download_%s", resp.TaskId))
 	if err != nil {
 		return nil, fmt.Errorf("Failed to create temporary dir: %s", err)
 	}
@@ -1254,7 +1254,7 @@
 		return nil, fmt.Errorf("Could not download %s: %s", outputDigest, err)
 	}
 	outputFile := filepath.Join(outputDir, BUILD_OUTPUT_FILENAME)
-	contents, err := ioutil.ReadFile(outputFile)
+	contents, err := os.ReadFile(outputFile)
 	if err != nil {
 		return nil, fmt.Errorf("Could not read outputfile %s: %s", outputFile, err)
 	}
@@ -1447,7 +1447,7 @@
 	if res == nil || res.Size != uint64(len(patch)) {
 		// Patch does not exist in Google Storage yet so upload it.
 		patchPath := filepath.Join(os.TempDir(), patchFileName)
-		if err := ioutil.WriteFile(patchPath, []byte(patch), 0666); err != nil {
+		if err := os.WriteFile(patchPath, []byte(patch), 0666); err != nil {
 			return "", err
 		}
 		defer util.Remove(patchPath)
@@ -1466,7 +1466,7 @@
 		return "", fmt.Errorf("Could not fetch %s: %s", patchId, err)
 	}
 	defer util.Close(respBody)
-	patch, err := ioutil.ReadAll(respBody)
+	patch, err := io.ReadAll(respBody)
 	if err != nil {
 		return "", fmt.Errorf("Could not read from %s: %s", patchId, err)
 	}
@@ -1497,7 +1497,7 @@
 	if err != nil {
 		return err
 	}
-	if err := ioutil.WriteFile(filePath, b, 0644); err != nil {
+	if err := os.WriteFile(filePath, b, 0644); err != nil {
 		return err
 	}
 	return nil
diff --git a/ct/go/worker_scripts/isolate_telemetry/main.go b/ct/go/worker_scripts/isolate_telemetry/main.go
index 21ffeb0..76e5e90 100644
--- a/ct/go/worker_scripts/isolate_telemetry/main.go
+++ b/ct/go/worker_scripts/isolate_telemetry/main.go
@@ -6,7 +6,6 @@
 	"errors"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -90,7 +89,7 @@
 
 	// Record the isolate hash in the output file.
 	hashOutputFile := filepath.Join(*outDir, util.ISOLATE_TELEMETRY_FILENAME)
-	if err := ioutil.WriteFile(hashOutputFile, []byte(hash), os.ModePerm); err != nil {
+	if err := os.WriteFile(hashOutputFile, []byte(hash), os.ModePerm); err != nil {
 		return fmt.Errorf("Could not write to %s: %s", hashOutputFile, err)
 	}
 
diff --git a/ct/go/worker_scripts/metrics_analysis/main.go b/ct/go/worker_scripts/metrics_analysis/main.go
index 86db648..0da9b05 100644
--- a/ct/go/worker_scripts/metrics_analysis/main.go
+++ b/ct/go/worker_scripts/metrics_analysis/main.go
@@ -11,7 +11,6 @@
 	"errors"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"regexp"
@@ -81,7 +80,7 @@
 	// Download the trace URLs for this run from Google storage.
 	tracesFilename := *runID + ".traces.csv"
 	util.MkdirAll(util.PagesetsDir, 0700)
-	tmpDir, err := ioutil.TempDir(util.PagesetsDir, "traces")
+	tmpDir, err := os.MkdirTemp(util.PagesetsDir, "traces")
 	if err != nil {
 		return fmt.Errorf("Could not create tmpdir: %s", err)
 	}
diff --git a/ct/go/worker_scripts/run_chromium_analysis/main.go b/ct/go/worker_scripts/run_chromium_analysis/main.go
index 3a1234a..24b905b 100644
--- a/ct/go/worker_scripts/run_chromium_analysis/main.go
+++ b/ct/go/worker_scripts/run_chromium_analysis/main.go
@@ -89,7 +89,7 @@
 		return err
 	}
 
-	tmpDir, err := ioutil.TempDir("", "patches")
+	tmpDir, err := os.MkdirTemp("", "patches")
 	remotePatchesDir := path.Join(util.ChromiumAnalysisRunsStorageDir, *runID)
 
 	// Download the custom webpages for this run from Google storage.
diff --git a/ct/go/worker_scripts/run_chromium_perf/main.go b/ct/go/worker_scripts/run_chromium_perf/main.go
index 57925a7..6257306 100644
--- a/ct/go/worker_scripts/run_chromium_perf/main.go
+++ b/ct/go/worker_scripts/run_chromium_perf/main.go
@@ -87,7 +87,7 @@
 		return err
 	}
 
-	tmpDir, err := ioutil.TempDir("", "patches")
+	tmpDir, err := os.MkdirTemp("", "patches")
 	remotePatchesDir := path.Join(util.ChromiumPerfRunsStorageDir, *runID)
 
 	// Download the custom webpages for this run from Google storage.
diff --git a/datahopper/go/datahopper/jobs_test.go b/datahopper/go/datahopper/jobs_test.go
index 259513d..7bb8b40 100644
--- a/datahopper/go/datahopper/jobs_test.go
+++ b/datahopper/go/datahopper/jobs_test.go
@@ -5,7 +5,7 @@
 	"context"
 	"encoding/gob"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"testing"
 	"time"
 
@@ -370,7 +370,7 @@
 
 func TestOverdueJobSpecMetrics(t *testing.T) {
 
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, wd)
 
diff --git a/datahopper/go/swarming_metrics/tasks_test.go b/datahopper/go/swarming_metrics/tasks_test.go
index 8dbf16e..019c47d 100644
--- a/datahopper/go/swarming_metrics/tasks_test.go
+++ b/datahopper/go/swarming_metrics/tasks_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"testing"
 	"time"
 
@@ -80,7 +80,7 @@
 func TestLoadSwarmingTasks(t *testing.T) {
 
 	ctx := context.Background()
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, wd)
 
@@ -159,7 +159,7 @@
 func TestMetrics(t *testing.T) {
 
 	ctx := context.Background()
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, wd)
 
@@ -242,7 +242,7 @@
 func TestPerfUpload(t *testing.T) {
 
 	ctx := context.Background()
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, wd)
 
diff --git a/debugger-app/go/debugger-app/main.go b/debugger-app/go/debugger-app/main.go
index a32e040..7b8631f 100644
--- a/debugger-app/go/debugger-app/main.go
+++ b/debugger-app/go/debugger-app/main.go
@@ -2,9 +2,9 @@
 
 import (
 	"flag"
-	"io/ioutil"
 	"mime"
 	"net/http"
+	"os"
 	"path/filepath"
 	"strings"
 
@@ -52,13 +52,13 @@
 }
 
 func loadPages(resourceDir string) {
-	p, err := ioutil.ReadFile(filepath.Join(resourceDir, "main.html"))
+	p, err := os.ReadFile(filepath.Join(resourceDir, "main.html"))
 	if err != nil {
 		sklog.Fatalf("Could not find index html: %s", err)
 	}
 	indexPage = p
 
-	p, err = ioutil.ReadFile(filepath.Join(resourceDir, "versions.html"))
+	p, err = os.ReadFile(filepath.Join(resourceDir, "versions.html"))
 	if err != nil {
 		sklog.Fatalf("Could not find index html: %s", err)
 	}
diff --git a/demos/go/demoserver/main.go b/demos/go/demoserver/main.go
index a155ac1..85274d5 100644
--- a/demos/go/demoserver/main.go
+++ b/demos/go/demoserver/main.go
@@ -7,7 +7,6 @@
 	"encoding/json"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"path/filepath"
@@ -52,7 +51,7 @@
 		sklog.Fatalf("Failed to setup git: %s", err)
 	}
 	// Create a threadsafe checkout to serve from.
-	checkoutDir, err := ioutil.TempDir("", "demos_repo")
+	checkoutDir, err := os.MkdirTemp("", "demos_repo")
 	if err != nil {
 		sklog.Fatalf("Unable to create temporary directory for demos checkout: %s", err)
 	}
@@ -147,7 +146,7 @@
 		return skerr.Wrap(err)
 	}
 	metadataPath := filepath.Join(s.demoPath, "metadata.json")
-	err = ioutil.WriteFile(metadataPath, obj, 0644)
+	err = os.WriteFile(metadataPath, obj, 0644)
 	if err != nil {
 		return skerr.Wrapf(err, "Unable to write json to '%s'.", metadataPath)
 	}
diff --git a/docsyserver/go/docset/docset_test.go b/docsyserver/go/docset/docset_test.go
index 28d6207..2d8a454 100644
--- a/docsyserver/go/docset/docset_test.go
+++ b/docsyserver/go/docset/docset_test.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -344,7 +343,7 @@
 	// Note that the old _index.md was removed and re-symlinked successfully.
 	require.FileExists(t, filepath.Join(src, "_index.md"))
 	// And we have written over an old file.
-	b, err := ioutil.ReadFile(filepath.Join(src, "users.md"))
+	b, err := os.ReadFile(filepath.Join(src, "users.md"))
 	require.NoError(t, err)
 	require.Equal(t, contents, string(b))
 }
diff --git a/ds/go/backup/backup.go b/ds/go/backup/backup.go
index b50df02..d900470 100644
--- a/ds/go/backup/backup.go
+++ b/ds/go/backup/backup.go
@@ -11,7 +11,7 @@
 	"bytes"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"strings"
 	"time"
@@ -98,7 +98,7 @@
 		} else {
 			sklog.Infof("Successfully started backup: %s-%v", ns, kinds)
 		}
-		bodyBytes, err := ioutil.ReadAll(resp.Body)
+		bodyBytes, err := io.ReadAll(resp.Body)
 		if err != nil {
 			sklog.Errorf("Failed to read response: %s-%v: %s", ns, kinds, err)
 			success = false
diff --git a/email/go/emailclient/emailclient_test.go b/email/go/emailclient/emailclient_test.go
index 8583a11..1df0594 100644
--- a/email/go/emailclient/emailclient_test.go
+++ b/email/go/emailclient/emailclient_test.go
@@ -1,7 +1,7 @@
 package emailclient
 
 import (
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/http/httptest"
 	"testing"
@@ -27,7 +27,7 @@
 </html>
 `
 	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		b, err := ioutil.ReadAll(r.Body)
+		b, err := io.ReadAll(r.Body)
 		require.NoError(t, err)
 		bodyAsString := string(b)
 		require.Equal(t, expected, bodyAsString)
@@ -69,7 +69,7 @@
 </html>
 `
 	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		b, err := ioutil.ReadAll(r.Body)
+		b, err := io.ReadAll(r.Body)
 		require.NoError(t, err)
 		bodyAsString := string(b)
 		require.Equal(t, expected, bodyAsString)
diff --git a/email/go/emailservice/emailservice.go b/email/go/emailservice/emailservice.go
index d43838e..c50b2a6 100644
--- a/email/go/emailservice/emailservice.go
+++ b/email/go/emailservice/emailservice.go
@@ -7,7 +7,6 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"time"
 
@@ -91,7 +90,7 @@
 
 func convertRFC2822ToSendGrid(r io.Reader) (*mail.SGMailV3, error) {
 	// Parse the entire incoming RFC2822 body.
-	body, err := ioutil.ReadAll(r)
+	body, err := io.ReadAll(r)
 	if err != nil {
 		return nil, skerr.Wrapf(err, "Failed to read body.")
 	}
@@ -197,7 +196,7 @@
 					sklog.Infof("Echo request failed: %s", err)
 					continue
 				}
-				b, err := ioutil.ReadAll(resp.Body)
+				b, err := io.ReadAll(resp.Body)
 				if err != nil {
 					sklog.Infof("Echo Reading response body failed: %s", err)
 					continue
diff --git a/fiddlek/go/client/client.go b/fiddlek/go/client/client.go
index 7810f84..335a7dc 100644
--- a/fiddlek/go/client/client.go
+++ b/fiddlek/go/client/client.go
@@ -4,7 +4,7 @@
 	"bytes"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"time"
 
@@ -38,7 +38,7 @@
 			sklog.Fatalf("Send failed, with fail_fast set: %s", resp.Status)
 		}
 		body := "(no body found)"
-		b, err := ioutil.ReadAll(resp.Body)
+		b, err := io.ReadAll(resp.Body)
 		if err == nil {
 			body = string(b)
 		}
diff --git a/fiddlek/go/fiddlecli/main.go b/fiddlek/go/fiddlecli/main.go
index dee9f84..7df6a76 100644
--- a/fiddlek/go/fiddlecli/main.go
+++ b/fiddlek/go/fiddlecli/main.go
@@ -9,7 +9,6 @@
 	"encoding/json"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"log"
 	"os"
 	"sync"
@@ -61,7 +60,7 @@
 	}
 
 	// Read the source JSON file.
-	b, err := ioutil.ReadFile(*input)
+	b, err := os.ReadFile(*input)
 	if err != nil {
 		log.Fatalf("Failed to read %s: %s", *input, err)
 	}
@@ -70,7 +69,7 @@
 		log.Fatalf("%s does not contain valid JSON: %s", *input, err)
 	}
 	lastWritten := types.BulkResponse{}
-	b, err = ioutil.ReadFile(*output)
+	b, err = os.ReadFile(*output)
 	if err == nil {
 		if err := json.Unmarshal(b, &lastWritten); err != nil {
 			lastWritten = nil
@@ -159,7 +158,7 @@
 	if err != nil {
 		log.Fatalf("Failed to encode response file: %s", err)
 	}
-	if err := ioutil.WriteFile(*output, b, 0600); err != nil {
+	if err := os.WriteFile(*output, b, 0600); err != nil {
 		log.Fatalf("Failed to write response file: %s", err)
 	}
 }
diff --git a/fiddlek/go/fiddler/main.go b/fiddlek/go/fiddler/main.go
index 21a1230..1773fb3 100644
--- a/fiddlek/go/fiddler/main.go
+++ b/fiddlek/go/fiddler/main.go
@@ -10,8 +10,8 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
+	"os"
 	"path"
 	"path/filepath"
 	"runtime"
@@ -145,7 +145,7 @@
 	}()
 
 	// Compile draw.cpp into 'fiddle'.
-	if err := ioutil.WriteFile(filepath.Join(*checkout, "tools", "fiddle", "draw.cpp"), []byte(request.Code), 0644); err != nil {
+	if err := os.WriteFile(filepath.Join(*checkout, "tools", "fiddle", "draw.cpp"), []byte(request.Code), 0644); err != nil {
 		res.Execute.Errors = fmt.Sprintf("Failed to write draw.cpp: %s", err)
 		serializeOutput(ctx, w, res)
 		return
@@ -183,7 +183,7 @@
 		//   - Clean up tmp file.
 		//   - Encode resulting webm files as base64 strings and return in JSON.
 		numFrames := int(FPS * (request.Options.Duration))
-		tmpDir, err := ioutil.TempDir("", "animation")
+		tmpDir, err := os.MkdirTemp("", "animation")
 		defer util.RemoveAll(tmpDir)
 		if err != nil {
 			res.Execute.Errors = fmt.Sprintf("Failed to create tmp dir for storing animation PNGs: %s", err)
@@ -272,7 +272,7 @@
 
 // encodeWebm encodes the webm as base64 and adds it to the results.
 func encodeWebm(prefix, tmpDir string, res *types.Result) string {
-	b, err := ioutil.ReadFile(path.Join(tmpDir, fmt.Sprintf("%s.webm", prefix)))
+	b, err := os.ReadFile(path.Join(tmpDir, fmt.Sprintf("%s.webm", prefix)))
 	if err != nil {
 		res.Execute.Errors = fmt.Sprintf("Failed to read resulting video: %s", err)
 		return ""
@@ -315,7 +315,7 @@
 		res.Execute.Errors = fmt.Sprintf("Failed to decode frame %d of %s: %s", i, prefix, err)
 		return err
 	}
-	if err := ioutil.WriteFile(path.Join(tmpDir, fmt.Sprintf("%s_%05d.png", prefix, i)), body, 0600); err != nil {
+	if err := os.WriteFile(path.Join(tmpDir, fmt.Sprintf("%s_%05d.png", prefix, i)), body, 0600); err != nil {
 		res.Execute.Errors = fmt.Sprintf("Failed to write frame %d of %s as a PNG: %s", i, prefix, err)
 		return err
 	}
@@ -385,7 +385,7 @@
 		defer span.End()
 	}
 
-	b, err := ioutil.ReadFile(filepath.Join(*checkout, "VERSION"))
+	b, err := os.ReadFile(filepath.Join(*checkout, "VERSION"))
 	if err != nil {
 		sklog.Fatalf("Failed to read Skia version: %s", err)
 	}
diff --git a/fiddlek/go/store/store.go b/fiddlek/go/store/store.go
index c706e88..d554ee8 100644
--- a/fiddlek/go/store/store.go
+++ b/fiddlek/go/store/store.go
@@ -5,7 +5,7 @@
 	"context"
 	"encoding/base64"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"reflect"
 	"regexp"
 	"sort"
@@ -382,7 +382,7 @@
 	if err != nil {
 		return "", nil, fmt.Errorf("Failed to open source file for %s: %s", fiddleHash, err)
 	}
-	b, err := ioutil.ReadAll(r)
+	b, err := io.ReadAll(r)
 	if err != nil {
 		return "", nil, fmt.Errorf("Failed to read source file for %s: %s", fiddleHash, err)
 	}
@@ -486,7 +486,7 @@
 		}
 	}
 	defer util.Close(r)
-	b, err := ioutil.ReadAll(r)
+	b, err := io.ReadAll(r)
 	if err != nil {
 		return nil, "", "", fmt.Errorf("Unable to read the media file (%s, %s): %s", fiddleHash, string(media), err)
 	}
@@ -550,7 +550,7 @@
 		return "", fmt.Errorf("Failed to open reader for name %q: %s", name, err)
 	}
 	defer util.Close(r)
-	b, err := ioutil.ReadAll(r)
+	b, err := io.ReadAll(r)
 	if err != nil {
 		return "", fmt.Errorf("Failed to read named file %q: %s", name, err)
 	}
diff --git a/get_service_account/go/get_service_account/main.go b/get_service_account/go/get_service_account/main.go
index 498a609..a758a49 100644
--- a/get_service_account/go/get_service_account/main.go
+++ b/get_service_account/go/get_service_account/main.go
@@ -5,7 +5,7 @@
 import (
 	"context"
 	"encoding/json"
-	"io/ioutil"
+	"os"
 
 	"go.skia.org/infra/go/exec"
 	"go.skia.org/infra/go/metadata"
@@ -73,7 +73,7 @@
 	if body == "" {
 		sklog.Fatalf("Failed to find the JST service account in the metadata.")
 	}
-	if err := ioutil.WriteFile(OUTPUT_FILENAME, []byte(body), 0600); err != nil {
+	if err := os.WriteFile(OUTPUT_FILENAME, []byte(body), 0600); err != nil {
 		sklog.Fatalf("Failed to write %q: %s", OUTPUT_FILENAME, err)
 	}
 }
diff --git a/gitsync/go/gitsync/main.go b/gitsync/go/gitsync/main.go
index 29dbfe6..0cb6635 100644
--- a/gitsync/go/gitsync/main.go
+++ b/gitsync/go/gitsync/main.go
@@ -3,9 +3,9 @@
 import (
 	"context"
 	"flag"
-	"io/ioutil"
 	"log"
 	"net/http"
+	"os"
 	"strings"
 	"time"
 
@@ -73,7 +73,7 @@
 
 	// If a configuration file was given we load it into config.
 	if *configFile != "" {
-		confBytes, err := ioutil.ReadFile(*configFile)
+		confBytes, err := os.ReadFile(*configFile)
 		if err != nil {
 			sklog.Fatalf("Error reading config file %s: %s", *configFile, err)
 		}
diff --git a/gitsync/go/watcher/watcher_test.go b/gitsync/go/watcher/watcher_test.go
index 57608de..ee77d57 100644
--- a/gitsync/go/watcher/watcher_test.go
+++ b/gitsync/go/watcher/watcher_test.go
@@ -4,8 +4,8 @@
 	"context"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"net/http"
+	"os"
 	"strings"
 	"sync"
 	"testing"
@@ -379,7 +379,7 @@
 // setupGitsync performs common setup for GitStore based Graphs.
 func setupGitsync(t *testing.T) (context.Context, *git_testutils.GitBuilder, *repograph.Graph, *gitsyncRefresher, func()) {
 	ctx, g, cleanup := repograph_shared_tests.CommonSetup(t)
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer util.RemoveAll(wd)
 	_, _, gs := gitstore_testutils.SetupAndLoadBTGitStore(t, ctx, wd, g.RepoUrl(), true)
diff --git a/go/auth/auth.go b/go/auth/auth.go
index 45f140d..84a9382 100644
--- a/go/auth/auth.go
+++ b/go/auth/auth.go
@@ -6,7 +6,6 @@
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"time"
@@ -279,7 +278,7 @@
 		sklog.Infof("Read JWT from metadata %s", metadataName)
 		return []byte(jwt), nil
 	}
-	body, err := ioutil.ReadFile(fileName)
+	body, err := os.ReadFile(fileName)
 	if err == nil {
 		sklog.Infof("Read JWT from file %s", fileName)
 		return body, nil
diff --git a/go/buildskia/buildskia_test.go b/go/buildskia/buildskia_test.go
index 1d216d7..fbd615b 100644
--- a/go/buildskia/buildskia_test.go
+++ b/go/buildskia/buildskia_test.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -50,7 +49,7 @@
 	ctx := cipd_git.UseGitFinder(context.Background())
 	ctx = exec.NewContext(ctx, mock.Run)
 
-	checkout, err := ioutil.TempDir("", "download-test")
+	checkout, err := os.MkdirTemp("", "download-test")
 	require.NoError(t, err)
 	defer func() {
 		err := os.RemoveAll(checkout)
diff --git a/go/buildskia/continuous.go b/go/buildskia/continuous.go
index 4c2ef7c..8e8c30c 100644
--- a/go/buildskia/continuous.go
+++ b/go/buildskia/continuous.go
@@ -4,7 +4,7 @@
 	"context"
 	"errors"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"os"
 	"path"
 	"path/filepath"
@@ -255,7 +255,7 @@
 		return nil, fmt.Errorf("Failed to open %s for reading: %s", GOOD_BUILDS_FILENAME, err)
 	}
 	defer util.Close(fi)
-	buf, err := ioutil.ReadAll(fi)
+	buf, err := io.ReadAll(fi)
 	if err != nil {
 		return nil, fmt.Errorf("Failed to read: %s", err)
 	}
diff --git a/go/buildskia/continuous_test.go b/go/buildskia/continuous_test.go
index 3abf8a5..a2abc72 100644
--- a/go/buildskia/continuous_test.go
+++ b/go/buildskia/continuous_test.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -17,7 +16,7 @@
 )
 
 func setupTemp(t *testing.T, testData []string, repo vcsinfo.VCS) (*ContinuousBuilder, func()) {
-	tempDir, err := ioutil.TempDir("", "builder_test_")
+	tempDir, err := os.MkdirTemp("", "builder_test_")
 	assert.NoError(t, err)
 	fi, err := os.Create(filepath.Join(tempDir, GOOD_BUILDS_FILENAME))
 	assert.NoError(t, err)
diff --git a/go/cas/rbe/rbe_manual_test.go b/go/cas/rbe/rbe_manual_test.go
index c7a888e..9491b1c 100644
--- a/go/cas/rbe/rbe_manual_test.go
+++ b/go/cas/rbe/rbe_manual_test.go
@@ -2,7 +2,6 @@
 
 import (
 	"context"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -54,7 +53,7 @@
 			isExecutable: info.Mode()&0111 != 0,
 		}
 		if !info.IsDir() {
-			contents, err := ioutil.ReadFile(path)
+			contents, err := os.ReadFile(path)
 			if err != nil {
 				return err
 			}
@@ -79,13 +78,13 @@
 // which adds files and directories, then uploads and downloads, asserting that
 // the resulting directory is identical.
 func testUploadDownload(ctx context.Context, t *testing.T, client *Client, work func(string)) {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, wd)
 	work(wd)
 	digest, err := client.Upload(ctx, wd, []string{"."}, nil)
 	require.NoError(t, err)
-	dest, err := ioutil.TempDir("", "")
+	dest, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, dest)
 	require.NoError(t, client.Download(ctx, dest, digest))
@@ -105,7 +104,7 @@
 	if executable {
 		mode |= 0111
 	}
-	require.NoError(t, ioutil.WriteFile(filepath.Join(wd, name), []byte(contents), mode))
+	require.NoError(t, os.WriteFile(filepath.Join(wd, name), []byte(contents), mode))
 }
 
 func TestUploadDownload(t *testing.T) {
@@ -154,7 +153,7 @@
 
 	// upload is a helper function for creating and uploading a directory tree.
 	upload := func(work func(string)) (string, map[string]*node) {
-		wd, err := ioutil.TempDir("", "")
+		wd, err := os.MkdirTemp("", "")
 		require.NoError(t, err)
 		defer testutils.RemoveAll(t, wd)
 		work(wd)
@@ -184,7 +183,7 @@
 	// Merge the digests.
 	mergeDigest, err := client.Merge(ctx, []string{digest1, digest2})
 	require.NoError(t, err)
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, wd)
 	require.NoError(t, client.Download(ctx, wd, mergeDigest))
@@ -212,7 +211,7 @@
 func TestUpload_Exclude(t *testing.T) {
 	ctx, client := setup(t)
 
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, wd)
 
@@ -221,7 +220,7 @@
 
 	digest, err := client.Upload(ctx, wd, []string{"."}, []string{".*ipm.*"})
 	require.NoError(t, err)
-	dest, err := ioutil.TempDir("", "")
+	dest, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, dest)
 	require.NoError(t, client.Download(ctx, dest, digest))
@@ -239,7 +238,7 @@
 	f(t, wd, "fake.git", "blahblah", false)
 	digest, err = client.Upload(ctx, wd, []string{"."}, []string{".*ipm.*", ExcludeGitDir})
 	require.NoError(t, err)
-	dest, err = ioutil.TempDir("", "")
+	dest, err = os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, dest)
 	require.NoError(t, client.Download(ctx, dest, digest))
diff --git a/go/cipd/cipd.go b/go/cipd/cipd.go
index 23dd2f0..ab19866 100644
--- a/go/cipd/cipd.go
+++ b/go/cipd/cipd.go
@@ -10,7 +10,6 @@
 	"context"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"path/filepath"
@@ -331,7 +330,7 @@
 	}
 
 	// Create the package file.
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	if err != nil {
 		return common.Pin{}, skerr.Wrap(err)
 	}
diff --git a/go/cipd/gen_versions.go b/go/cipd/gen_versions.go
index 511de90..8eff12b 100644
--- a/go/cipd/gen_versions.go
+++ b/go/cipd/gen_versions.go
@@ -55,7 +55,7 @@
 	}
 	for _, e := range entries {
 		if e.IsDir() {
-			contents, err := ioutil.ReadFile(path.Join(assetsDir, e.Name(), "VERSION"))
+			contents, err := os.ReadFile(path.Join(assetsDir, e.Name(), "VERSION"))
 			if err == nil {
 				name := e.Name()
 				fullName := fmt.Sprintf("skia/bots/%s", name)
diff --git a/go/config/config.go b/go/config/config.go
index 4a0074f..51b438e 100644
--- a/go/config/config.go
+++ b/go/config/config.go
@@ -3,7 +3,7 @@
 import (
 	"encoding"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"time"
 
 	"github.com/flynn/json5"
@@ -41,7 +41,7 @@
 	if flagName != "" {
 		flagName = flagName + " "
 	}
-	if data, err := ioutil.ReadFile(path); err != nil {
+	if data, err := os.ReadFile(path); err != nil {
 		return fmt.Errorf("Unable to read %sfile %q: %s", flagName, path, err)
 	} else if err := json5.Unmarshal(data, out); err != nil {
 		return fmt.Errorf("Unable to parse %sfile %q: %s", flagName, path, err)
diff --git a/go/config/config_test.go b/go/config/config_test.go
index 53079a2..3c5b9a5 100644
--- a/go/config/config_test.go
+++ b/go/config/config_test.go
@@ -2,7 +2,6 @@
 
 import (
 	"encoding/json"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -93,7 +92,7 @@
 func TestParseConfigFileInvalid(t *testing.T) {
 	dir := t.TempDir()
 	configFile := filepath.Join(dir, "invalid.json5")
-	require.NoError(t, ioutil.WriteFile(configFile, []byte("Hi Mom!"), os.ModePerm))
+	require.NoError(t, os.WriteFile(configFile, []byte("Hi Mom!"), os.ModePerm))
 	parsed := TestConfig{}
 	err := ParseConfigFile(configFile, "", &parsed)
 	require.Error(t, err)
diff --git a/go/counters/counters_test.go b/go/counters/counters_test.go
index 179d6ef..2bc0013 100644
--- a/go/counters/counters_test.go
+++ b/go/counters/counters_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"testing"
 	"time"
 
@@ -91,7 +91,7 @@
 		timeNowFunc = time.Now
 	}()
 
-	w, err := ioutil.TempDir("", "")
+	w, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, w)
 
diff --git a/go/cq/update.go b/go/cq/update.go
index 889299a..3a8e3b4 100644
--- a/go/cq/update.go
+++ b/go/cq/update.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"io"
-	"io/ioutil"
+	"os"
 	osexec "os/exec"
 	"path/filepath"
 	"regexp"
@@ -38,7 +38,7 @@
 	}
 
 	// Read the config file.
-	oldCfgBytes, err := ioutil.ReadFile(starlarkConfigFile)
+	oldCfgBytes, err := os.ReadFile(starlarkConfigFile)
 	if err != nil {
 		return skerr.Wrapf(err, "failed to read %s", starlarkConfigFile)
 	}
diff --git a/go/cq/update_manual_test.go b/go/cq/update_manual_test.go
index 96da662..2ef9731 100644
--- a/go/cq/update_manual_test.go
+++ b/go/cq/update_manual_test.go
@@ -2,7 +2,6 @@
 
 import (
 	"context"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -16,7 +15,7 @@
 
 	ctx := context.Background()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
diff --git a/go/docker/docker.go b/go/docker/docker.go
index 99eed8a..8ee641c0 100644
--- a/go/docker/docker.go
+++ b/go/docker/docker.go
@@ -6,7 +6,6 @@
 	"encoding/json"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"regexp"
 	"strconv"
@@ -370,7 +369,7 @@
 			return skerr.Wrap(err)
 		}
 		defer util.Close(resp.Body)
-		manifestBytes, err = ioutil.ReadAll(resp.Body)
+		manifestBytes, err = io.ReadAll(resp.Body)
 		if err != nil {
 			return skerr.Wrap(err)
 		}
diff --git a/go/exec/exec_test.go b/go/exec/exec_test.go
index 22fa35c..4059247 100644
--- a/go/exec/exec_test.go
+++ b/go/exec/exec_test.go
@@ -6,7 +6,6 @@
 	"errors"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -96,7 +95,7 @@
 
 func TestBasic(t *testing.T) {
 	unittest.BazelOnlyTest(t) // Uses the Bazel-downloaded python3 binary.
-	dir, err := ioutil.TempDir("", "exec_test")
+	dir, err := os.MkdirTemp("", "exec_test")
 	require.NoError(t, err)
 	defer RemoveAll(dir)
 	file := filepath.Join(dir, "ran")
@@ -111,7 +110,7 @@
 
 func TestEnv(t *testing.T) {
 	unittest.BazelOnlyTest(t) // Uses the Bazel-downloaded python3 binary.
-	dir, err := ioutil.TempDir("", "exec_test")
+	dir, err := os.MkdirTemp("", "exec_test")
 	require.NoError(t, err)
 	defer RemoveAll(dir)
 	file := filepath.Join(dir, "ran")
@@ -133,7 +132,7 @@
 
 func TestInheritPath(t *testing.T) {
 	unittest.BazelOnlyTest(t) // Uses the Bazel-downloaded python3 binary.
-	dir, err := ioutil.TempDir("", "exec_test")
+	dir, err := os.MkdirTemp("", "exec_test")
 	require.NoError(t, err)
 	defer RemoveAll(dir)
 	file := filepath.Join(dir, "ran")
@@ -147,7 +146,7 @@
 		Env:         []string{fmt.Sprintf("EXEC_TEST_FILE=%s", file)},
 		InheritPath: true,
 	}))
-	contents, err := ioutil.ReadFile(file)
+	contents, err := os.ReadFile(file)
 	require.NoError(t, err)
 	// Python may append site_packages dir to PATH.
 	expect.True(t, strings.Contains(strings.TrimSpace(string(contents)), os.Getenv("PATH")))
@@ -155,7 +154,7 @@
 
 func TestInheritEnv(t *testing.T) {
 	unittest.BazelOnlyTest(t) // Uses the Bazel-downloaded python3 binary.
-	dir, err := ioutil.TempDir("", "exec_test")
+	dir, err := os.MkdirTemp("", "exec_test")
 	require.NoError(t, err)
 	defer RemoveAll(dir)
 	file := filepath.Join(dir, "ran")
@@ -174,7 +173,7 @@
 		InheritPath: false,
 		InheritEnv:  true,
 	}))
-	contents, err := ioutil.ReadFile(file)
+	contents, err := os.ReadFile(file)
 	require.NoError(t, err)
 	lines := strings.Split(strings.TrimSpace(string(contents)), "\n")
 	require.Equal(t, 4, len(lines))
@@ -187,10 +186,10 @@
 
 func TestDir(t *testing.T) {
 	unittest.BazelOnlyTest(t) // Uses the Bazel-downloaded python3 binary.
-	dir1, err := ioutil.TempDir("", "exec_test1")
+	dir1, err := os.MkdirTemp("", "exec_test1")
 	require.NoError(t, err)
 	defer RemoveAll(dir1)
-	dir2, err := ioutil.TempDir("", "exec_test2")
+	dir2, err := os.MkdirTemp("", "exec_test2")
 	require.NoError(t, err)
 	defer RemoveAll(dir2)
 	require.NoError(t, Run(context.Background(), &Command{
@@ -218,7 +217,7 @@
 
 func TestError(t *testing.T) {
 	unittest.BazelOnlyTest(t) // Uses the Bazel-downloaded python3 binary.
-	dir, err := ioutil.TempDir("", "exec_test")
+	dir, err := os.MkdirTemp("", "exec_test")
 	require.NoError(t, err)
 	defer RemoveAll(dir)
 	output := bytes.Buffer{}
@@ -241,7 +240,7 @@
 
 func TestCombinedOutput(t *testing.T) {
 	unittest.BazelOnlyTest(t) // Uses the Bazel-downloaded python3 binary.
-	dir, err := ioutil.TempDir("", "exec_test")
+	dir, err := os.MkdirTemp("", "exec_test")
 	require.NoError(t, err)
 	defer RemoveAll(dir)
 	combined := bytes.Buffer{}
@@ -281,7 +280,7 @@
 
 func TestTimeoutNotReached(t *testing.T) {
 	unittest.BazelOnlyTest(t) // Uses the Bazel-downloaded python3 binary.
-	dir, err := ioutil.TempDir("", "exec_test")
+	dir, err := os.MkdirTemp("", "exec_test")
 	require.NoError(t, err)
 	defer RemoveAll(dir)
 	require.NoError(t, Run(context.Background(), &Command{
@@ -302,7 +301,7 @@
 
 func TestTimeoutExceeded(t *testing.T) {
 	unittest.BazelOnlyTest(t) // Uses the Bazel-downloaded python3 binary.
-	dir, err := ioutil.TempDir("", "exec_test")
+	dir, err := os.MkdirTemp("", "exec_test")
 	require.NoError(t, err)
 	defer RemoveAll(dir)
 	err = Run(context.Background(), &Command{
@@ -330,7 +329,7 @@
 		return nil
 	})
 
-	dir, err := ioutil.TempDir("", "exec_test")
+	dir, err := os.MkdirTemp("", "exec_test")
 	require.NoError(t, err)
 	defer RemoveAll(dir)
 	file := filepath.Join(dir, "ran")
@@ -356,7 +355,7 @@
 
 func TestRunCwd(t *testing.T) {
 	unittest.BazelOnlyTest(t) // Uses the Bazel-downloaded python3 binary.
-	dir, err := ioutil.TempDir("", "exec_test")
+	dir, err := os.MkdirTemp("", "exec_test")
 	require.NoError(t, err)
 	defer RemoveAll(dir)
 	output, err := RunCwd(context.Background(), dir, findPython3(t), "-u", "-c", "import os; print(os.getcwd())")
@@ -394,7 +393,7 @@
 	commands = mock.Commands()
 	require.Len(t, commands, 1)
 	expect.Equal(t, "grep -e ^ba", DebugString(commands[0]))
-	actualInput, err := ioutil.ReadAll(commands[0].Stdin)
+	actualInput, err := io.ReadAll(commands[0].Stdin)
 	require.NoError(t, err)
 	expect.Equal(t, inputString, string(actualInput))
 	expect.Equal(t, &output, commands[0].Stdout)
diff --git a/go/fileutil/fileutil.go b/go/fileutil/fileutil.go
index 4f2ada0..ebf084e 100644
--- a/go/fileutil/fileutil.go
+++ b/go/fileutil/fileutil.go
@@ -5,7 +5,6 @@
 	"crypto/sha1"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -118,7 +117,7 @@
 		return "", "", fmt.Errorf("Problem opening file %s: %s", path, err)
 	}
 	defer util.Close(f)
-	b, err := ioutil.ReadAll(f)
+	b, err := io.ReadAll(f)
 	if err != nil {
 		return "", "", fmt.Errorf("Problem reading file %s: %s", path, err)
 	}
@@ -181,7 +180,7 @@
 			}
 			return nil
 		}
-		b, err := ioutil.ReadFile(fp)
+		b, err := os.ReadFile(fp)
 		if err != nil {
 			return fmt.Errorf("Failed to read file: %s", err)
 		}
diff --git a/go/fileutil/fileutil_test.go b/go/fileutil/fileutil_test.go
index ae9b126..1d560c9 100644
--- a/go/fileutil/fileutil_test.go
+++ b/go/fileutil/fileutil_test.go
@@ -1,7 +1,6 @@
 package fileutil
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -44,14 +43,14 @@
 func TestReadAllFilesRecursive(t *testing.T) {
 
 	test := func(write, expect map[string]string, excludeDirs []string) {
-		wd, err := ioutil.TempDir("", "")
+		wd, err := os.MkdirTemp("", "")
 		require.NoError(t, err)
 		for k, v := range write {
 			dir := filepath.Dir(k)
 			if dir != "" {
 				require.NoError(t, os.MkdirAll(filepath.Join(wd, dir), os.ModePerm))
 			}
-			require.NoError(t, ioutil.WriteFile(filepath.Join(wd, k), []byte(v), os.ModePerm))
+			require.NoError(t, os.WriteFile(filepath.Join(wd, k), []byte(v), os.ModePerm))
 		}
 		actual, err := ReadAllFilesRecursive(wd, excludeDirs)
 		require.NoError(t, err)
diff --git a/go/gcs/download_helper.go b/go/gcs/download_helper.go
index b1e1d52..e65a7d6 100644
--- a/go/gcs/download_helper.go
+++ b/go/gcs/download_helper.go
@@ -5,7 +5,6 @@
 	"crypto/sha1"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"path"
 	"runtime"
@@ -80,7 +79,7 @@
 	}
 
 	var contents []byte
-	contents, err = ioutil.ReadFile(filepath)
+	contents, err = os.ReadFile(filepath)
 	if err != nil {
 		return skerr.Wrapf(err, "Failed to read %s", filepath)
 	}
diff --git a/go/gcs/download_helper_test.go b/go/gcs/download_helper_test.go
index 63cbeae..e50393e 100644
--- a/go/gcs/download_helper_test.go
+++ b/go/gcs/download_helper_test.go
@@ -4,7 +4,6 @@
 	"context"
 	"crypto/sha1"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"testing"
@@ -17,7 +16,7 @@
 func TestDownloadHelper(t *testing.T) {
 
 	// Setup.
-	workdir, err := ioutil.TempDir("", "")
+	workdir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, workdir)
 
@@ -35,7 +34,7 @@
 		if info.Mode() != 0755 {
 			return fmt.Errorf("Not executable")
 		}
-		contents, err := ioutil.ReadFile(fp)
+		contents, err := os.ReadFile(fp)
 		require.NoError(t, err)
 		sha1sum := fmt.Sprintf("%x", sha1.Sum(contents))
 		if sha1sum != hash {
@@ -57,13 +56,13 @@
 
 	// Modify the binary.
 	fakeContents := "blah blah blah"
-	require.NoError(t, ioutil.WriteFile(pathA, []byte(fakeContents), 0755))
+	require.NoError(t, os.WriteFile(pathA, []byte(fakeContents), 0755))
 	require.NotNil(t, check(a, hashA))
 
 	// Ensure that we end up with the right binary.
 	require.NoError(t, d.MaybeDownload(a, hashA))
 	require.NoError(t, check(a, hashA))
-	contents, err := ioutil.ReadFile(pathA)
+	contents, err := os.ReadFile(pathA)
 	require.NoError(t, err)
 	require.NotEqual(t, fakeContents, string(contents))
 
diff --git a/go/gcs/gcsclient/gcsclient.go b/go/gcs/gcsclient/gcsclient.go
index f3ece19..9a1fa10 100644
--- a/go/gcs/gcsclient/gcsclient.go
+++ b/go/gcs/gcsclient/gcsclient.go
@@ -4,7 +4,6 @@
 	"context"
 	"fmt"
 	"io"
-	"io/ioutil"
 
 	"cloud.google.com/go/storage"
 	"go.skia.org/infra/go/gcs"
@@ -68,7 +67,7 @@
 		return nil, err
 	}
 	defer util.Close(response)
-	return ioutil.ReadAll(response)
+	return io.ReadAll(response)
 }
 
 // See the GCSClient interface for more information about SetFileContents.
diff --git a/go/gcs/helpers.go b/go/gcs/helpers.go
index 0a00bb0..04deeb6 100644
--- a/go/gcs/helpers.go
+++ b/go/gcs/helpers.go
@@ -4,7 +4,6 @@
 	"context"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"strings"
 
@@ -42,7 +41,7 @@
 		return nil, err
 	}
 	defer util.Close(response)
-	return ioutil.ReadAll(response)
+	return io.ReadAll(response)
 }
 
 // AllFilesInDir synchronously iterates through all the files in a given Google Storage folder.
diff --git a/go/gcs/mem_gcsclient/memory_client.go b/go/gcs/mem_gcsclient/memory_client.go
index 325dba5..a092923 100644
--- a/go/gcs/mem_gcsclient/memory_client.go
+++ b/go/gcs/mem_gcsclient/memory_client.go
@@ -5,7 +5,6 @@
 	"compress/gzip"
 	"context"
 	"io"
-	"io/ioutil"
 	"strings"
 	"sync"
 
@@ -40,7 +39,7 @@
 	if !ok {
 		return nil, storage.ErrObjectNotExist
 	}
-	rv := ioutil.NopCloser(bytes.NewReader(contents))
+	rv := io.NopCloser(bytes.NewReader(contents))
 	// GCS automatically decodes gzip-encoded files. See
 	// https://cloud.google.com/storage/docs/transcoding. We do the same here so that tests acurately
 	// reflect what will happen when actually using GCS.
@@ -104,7 +103,7 @@
 	if err != nil {
 		return nil, err
 	}
-	return ioutil.ReadAll(r)
+	return io.ReadAll(r)
 }
 
 // See documentation for GCSClient interface.
diff --git a/go/gerrit/change_edit_helpers.go b/go/gerrit/change_edit_helpers.go
index 43f670d..bd51010 100644
--- a/go/gerrit/change_edit_helpers.go
+++ b/go/gerrit/change_edit_helpers.go
@@ -4,7 +4,7 @@
 	"context"
 	"errors"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 	"time"
@@ -148,7 +148,7 @@
 	changes := make(map[string]string, len(diffSplit))
 	for _, diffLine := range diffSplit {
 		if diffLine != "" {
-			contents, err := ioutil.ReadFile(filepath.Join(co.Dir(), diffLine))
+			contents, err := os.ReadFile(filepath.Join(co.Dir(), diffLine))
 			if err != nil {
 				return nil, skerr.Wrap(err)
 			}
diff --git a/go/gerrit/gerrit_test.go b/go/gerrit/gerrit_test.go
index a848bca..e14585a 100644
--- a/go/gerrit/gerrit_test.go
+++ b/go/gerrit/gerrit_test.go
@@ -5,7 +5,7 @@
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/http/httptest"
 	"testing"
@@ -670,7 +670,7 @@
 		require.Equal(t, "POST", r.Method)
 		w.WriteHeader(http.StatusCreated)
 		w.Header().Set("Content-Type", "application/json")
-		body, err := ioutil.ReadAll(r.Body)
+		body, err := io.ReadAll(r.Body)
 		require.NoError(t, err)
 		var data createChangePostData
 		require.NoError(t, json.Unmarshal(body, &data))
@@ -727,7 +727,7 @@
 		require.Equal(t, "POST", r.Method)
 		w.WriteHeader(http.StatusCreated)
 		w.Header().Set("Content-Type", "application/json")
-		body, err := ioutil.ReadAll(r.Body)
+		body, err := io.ReadAll(r.Body)
 		require.NoError(t, err)
 		var data createChangePostData
 		require.NoError(t, json.Unmarshal(body, &data))
@@ -786,7 +786,7 @@
 			"/a/changes/myProject~release~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1/cherrypick",
 			r.URL.Path)
 		w.Header().Set("Content-Type", "application/json")
-		body, err := ioutil.ReadAll(r.Body)
+		body, err := io.ReadAll(r.Body)
 		require.NoError(t, err)
 		var data cherryPickPostData
 		require.NoError(t, json.Unmarshal(body, &data))
diff --git a/go/git/checkout.go b/go/git/checkout.go
index 2173fb5..78f49a8 100644
--- a/go/git/checkout.go
+++ b/go/git/checkout.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -154,7 +153,7 @@
 // directory and then clones the repoUrl into a subdirectory, based on default
 // "git clone" behavior.
 func NewTempCheckout(ctx context.Context, repoUrl string) (*TempCheckout, error) {
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	if err != nil {
 		return nil, err
 	}
diff --git a/go/git/checkout_test.go b/go/git/checkout_test.go
index f945f0c..249d287 100644
--- a/go/git/checkout_test.go
+++ b/go/git/checkout_test.go
@@ -1,7 +1,6 @@
 package git
 
 import (
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -17,7 +16,7 @@
 	ctx, gb, commits := setup(t)
 	defer gb.Cleanup()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
@@ -82,21 +81,21 @@
 	}
 
 	// 1. Local modification (no git add).
-	require.NoError(t, ioutil.WriteFile(path.Join(c.Dir(), "somefile"), []byte("contents"), os.ModePerm))
+	require.NoError(t, os.WriteFile(path.Join(c.Dir(), "somefile"), []byte("contents"), os.ModePerm))
 	updateAndAssertClean()
 
 	// 2. Local modification (with git add).
-	require.NoError(t, ioutil.WriteFile(path.Join(c.Dir(), "somefile"), []byte("contents"), os.ModePerm))
+	require.NoError(t, os.WriteFile(path.Join(c.Dir(), "somefile"), []byte("contents"), os.ModePerm))
 	_, err = c.Git(ctx, "add", "somefile")
 	require.NoError(t, err)
 	updateAndAssertClean()
 
 	// 3. Untracked file.
-	require.NoError(t, ioutil.WriteFile(path.Join(c.Dir(), "untracked"), []byte("contents"), os.ModePerm))
+	require.NoError(t, os.WriteFile(path.Join(c.Dir(), "untracked"), []byte("contents"), os.ModePerm))
 	updateAndAssertClean()
 
 	// 4. Committed locally.
-	require.NoError(t, ioutil.WriteFile(path.Join(c.Dir(), "somefile"), []byte("contents"), os.ModePerm))
+	require.NoError(t, os.WriteFile(path.Join(c.Dir(), "somefile"), []byte("contents"), os.ModePerm))
 	_, err = c.Git(ctx, "commit", "-a", "-m", "msg")
 	require.NoError(t, err)
 	updateAndAssertClean()
@@ -108,7 +107,7 @@
 
 	test := func(name string, expectDirty bool, fn func(*testing.T, *Checkout)) {
 		t.Run(name, func(t *testing.T) {
-			tmp, err := ioutil.TempDir("", "")
+			tmp, err := os.MkdirTemp("", "")
 			require.NoError(t, err)
 			defer testutils.RemoveAll(t, tmp)
 			c, err := NewCheckout(ctx, gb.Dir(), tmp)
@@ -122,13 +121,13 @@
 
 	test("clean", false, func(t *testing.T, c *Checkout) {})
 	test("unstaged_changes", true, func(t *testing.T, c *Checkout) {
-		require.NoError(t, ioutil.WriteFile(filepath.Join(c.Dir(), checkedInFile), []byte("blahblah"), os.ModePerm))
+		require.NoError(t, os.WriteFile(filepath.Join(c.Dir(), checkedInFile), []byte("blahblah"), os.ModePerm))
 	})
 	test("untracked_file", true, func(t *testing.T, c *Checkout) {
-		require.NoError(t, ioutil.WriteFile(filepath.Join(c.Dir(), "untracked-file"), []byte("blahblah"), os.ModePerm))
+		require.NoError(t, os.WriteFile(filepath.Join(c.Dir(), "untracked-file"), []byte("blahblah"), os.ModePerm))
 	})
 	test("ahead_of_main", true, func(t *testing.T, c *Checkout) {
-		require.NoError(t, ioutil.WriteFile(filepath.Join(c.Dir(), checkedInFile), []byte("blahblah"), os.ModePerm))
+		require.NoError(t, os.WriteFile(filepath.Join(c.Dir(), checkedInFile), []byte("blahblah"), os.ModePerm))
 		_, err := c.Git(ctx, "commit", "-a", "-m", "updated file")
 		require.NoError(t, err)
 	})
diff --git a/go/git/gitdir_test.go b/go/git/gitdir_test.go
index c512c7a..160e2a1 100644
--- a/go/git/gitdir_test.go
+++ b/go/git/gitdir_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"fmt"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 	"testing"
@@ -41,7 +41,7 @@
 	ctx, gb, commits := setup(t)
 	defer gb.Cleanup()
 
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmpDir)
 
@@ -110,7 +110,7 @@
 	ctx, gb, commits := setup(t)
 	defer gb.Cleanup()
 
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmpDir)
 
@@ -138,7 +138,7 @@
 	ctx, gb, commits := setup(t)
 	defer gb.Cleanup()
 
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmpDir)
 
@@ -148,7 +148,7 @@
 	contents, err := g.GetFile(ctx, checkedInFile, "HEAD")
 	require.NoError(t, err)
 
-	contentsAtHead, err := ioutil.ReadFile(filepath.Join(g.Dir(), checkedInFile))
+	contentsAtHead, err := os.ReadFile(filepath.Join(g.Dir(), checkedInFile))
 	require.NoError(t, err)
 	require.Equal(t, string(contentsAtHead), contents)
 
@@ -163,7 +163,7 @@
 	ctx, gb, _ := setup(t)
 	defer gb.Cleanup()
 
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmpDir)
 
diff --git a/go/git/repo_test.go b/go/git/repo_test.go
index 57c516d..83060ab 100644
--- a/go/git/repo_test.go
+++ b/go/git/repo_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"strings"
 	"testing"
 
@@ -33,7 +33,7 @@
 	ctx, gb, commits := setup(t)
 	defer gb.Cleanup()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
@@ -68,7 +68,7 @@
 
 	// Verify that we can create a Checkout from the Repo. No need to test
 	// the Checkout since that struct has its own tests.
-	tmp2, err := ioutil.TempDir("", "")
+	tmp2, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp2)
 	_, err = r.Checkout(ctx, tmp2)
diff --git a/go/git/repograph/graph_test.go b/go/git/repograph/graph_test.go
index 8a4d1dd..a65e0ac 100644
--- a/go/git/repograph/graph_test.go
+++ b/go/git/repograph/graph_test.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"errors"
-	"io/ioutil"
 	"math/rand"
 	"os"
 	"path"
@@ -131,7 +130,7 @@
 // checkTopoSortGitBuilder creates a Graph from the given GitBuilder and
 // performs topological sorting tests on it.
 func checkTopoSortGitBuilder(t *testing.T, ctx context.Context, gb *git_testutils.GitBuilder, expect []string) {
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmpDir)
 	g, err := repograph.NewLocalGraph(ctx, gb.Dir(), tmpDir)
@@ -169,7 +168,7 @@
 	// timestamps might be equal. Adjust the expectations
 	// accordingly.
 	expect := []string{commits[4], commits[3], commits[2], commits[1], commits[0]}
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmpDir)
 	g, err := repograph.NewLocalGraph(ctx, gb.Dir(), tmpDir)
@@ -268,7 +267,7 @@
 	defer gb.Cleanup()
 	commits := git_testutils.GitSetup(ctx, gb)
 
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmpDir)
 	d1 := path.Join(tmpDir, "1")
diff --git a/go/git/repograph/local_serialize_test.go b/go/git/repograph/local_serialize_test.go
index 0cb0d5f..3325816 100644
--- a/go/git/repograph/local_serialize_test.go
+++ b/go/git/repograph/local_serialize_test.go
@@ -3,7 +3,7 @@
 import (
 	"bytes"
 	"context"
-	"io/ioutil"
+	"os"
 	"testing"
 
 	"github.com/stretchr/testify/require"
@@ -19,7 +19,7 @@
 	g := git_testutils.GitInit(t, ctx)
 	defer g.Cleanup()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
diff --git a/go/git/repograph/local_test.go b/go/git/repograph/local_test.go
index 9004f03..0f45e8d 100644
--- a/go/git/repograph/local_test.go
+++ b/go/git/repograph/local_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"os"
 	"testing"
 
 	"github.com/stretchr/testify/require"
@@ -23,7 +23,7 @@
 func setupRepo(t *testing.T) (context.Context, *git_testutils.GitBuilder, *repograph.Graph, shared_tests.RepoImplRefresher, func()) {
 	ctx, g, cleanup := shared_tests.CommonSetup(t)
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	repo, err := repograph.NewLocalGraph(ctx, g.Dir(), tmp)
diff --git a/go/git/repograph/shared_tests/shared_tests.go b/go/git/repograph/shared_tests/shared_tests.go
index bf799eb..92d73d5 100644
--- a/go/git/repograph/shared_tests/shared_tests.go
+++ b/go/git/repograph/shared_tests/shared_tests.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"reflect"
@@ -235,7 +234,7 @@
 	require.Equal(t, 3, c5.Index)
 
 	// Ensure that we can start in an empty dir and check out from scratch properly.
-	tmp2, err := ioutil.TempDir("", "")
+	tmp2, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp2)
 	repo2, err := repograph.NewLocalGraph(ctx, g.Dir(), tmp2)
@@ -701,7 +700,7 @@
 
 func TestRevList(t sktest.TestingT, ctx context.Context, gb *git_testutils.GitBuilder, repo *repograph.Graph, rf RepoImplRefresher) {
 	commits := git_testutils.GitSetup(ctx, gb)
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmpDir)
 	d1 := path.Join(tmpDir, "1")
diff --git a/go/git/testutils/git_builder.go b/go/git/testutils/git_builder.go
index aaa30af..de84e23 100644
--- a/go/git/testutils/git_builder.go
+++ b/go/git/testutils/git_builder.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"math/rand"
 	"os"
 	"path"
@@ -28,7 +27,7 @@
 
 // GitInit calls GitInitWithDefaultBranch with MainBranch.
 func GitInit(t sktest.TestingT, ctx context.Context) *GitBuilder {
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	return GitInitWithDir(t, ctx, tmp, git_common.MainBranch)
@@ -38,7 +37,7 @@
 // specified default branch and returns a GitBuilder to manage it. Call Cleanup to
 // remove the temporary directory. The current branch will be the main branch.
 func GitInitWithDefaultBranch(t sktest.TestingT, ctx context.Context, defaultBranch string) *GitBuilder {
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	return GitInitWithDir(t, ctx, tmp, defaultBranch)
@@ -119,7 +118,7 @@
 	if dir != "" {
 		require.NoError(g.t, os.MkdirAll(dir, os.ModePerm))
 	}
-	require.NoError(g.t, ioutil.WriteFile(fullPath, []byte(contents), os.ModePerm))
+	require.NoError(g.t, os.WriteFile(fullPath, []byte(contents), os.ModePerm))
 }
 
 func (g *GitBuilder) push(ctx context.Context) {
diff --git a/go/github/github.go b/go/github/github.go
index 4da727a..d9ce32e 100644
--- a/go/github/github.go
+++ b/go/github/github.go
@@ -18,7 +18,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"strings"
 	"time"
@@ -512,7 +512,7 @@
 	if resp.StatusCode != http.StatusOK {
 		return "", fmt.Errorf("Unexpected status code %d from %s", resp.StatusCode, githubContentURL)
 	}
-	bodyBytes, err := ioutil.ReadAll(resp.Body)
+	bodyBytes, err := io.ReadAll(resp.Body)
 	if err != nil {
 		return "", fmt.Errorf("Could not read from %s: %s", githubContentURL, err)
 	}
diff --git a/go/gitiles/testutils/testutils.go b/go/gitiles/testutils/testutils.go
index c16622b..e364a13 100644
--- a/go/gitiles/testutils/testutils.go
+++ b/go/gitiles/testutils/testutils.go
@@ -9,7 +9,7 @@
 	"encoding/base64"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"io"
 
 	"github.com/stretchr/testify/require"
 	"go.skia.org/infra/go/git"
@@ -47,7 +47,7 @@
 	}()
 	f, err := fs.Open(ctx, srcPath)
 	require.NoError(mr.t, err)
-	contents, err := ioutil.ReadAll(vfs.WithContext(ctx, f))
+	contents, err := io.ReadAll(vfs.WithContext(ctx, f))
 	require.NoError(mr.t, err)
 	st, err := f.Stat(ctx)
 	require.NoError(mr.t, err)
diff --git a/go/gitstore/pubsub/pubsub_test.go b/go/gitstore/pubsub/pubsub_test.go
index f4e091f..fc3cfe5 100644
--- a/go/gitstore/pubsub/pubsub_test.go
+++ b/go/gitstore/pubsub/pubsub_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"os"
 	"testing"
 	"time"
 
@@ -104,7 +104,7 @@
 	gb := git_testutils.GitInit(t, ctx)
 	defer gb.Cleanup()
 	gd := git.GitDir(gb.Dir())
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	assert.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 	graph, err := repograph.NewLocalGraph(ctx, gb.RepoUrl(), tmp)
diff --git a/go/httputils/http_test.go b/go/httputils/http_test.go
index baaaead..95413b4 100644
--- a/go/httputils/http_test.go
+++ b/go/httputils/http_test.go
@@ -4,7 +4,6 @@
 	"context"
 	"errors"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
 	"strconv"
@@ -214,7 +213,7 @@
 	h.ServeHTTP(w, r)
 	require.Equal(t, 200, w.Result().StatusCode)
 	require.Equal(t, "", w.Result().Header.Get("Location"))
-	b, err := ioutil.ReadAll(w.Result().Body)
+	b, err := io.ReadAll(w.Result().Body)
 	require.NoError(t, err)
 	require.Len(t, b, 12)
 
@@ -232,7 +231,7 @@
 	h.ServeHTTP(w, r)
 	require.Equal(t, 200, w.Result().StatusCode)
 	require.Equal(t, "", w.Result().Header.Get("Location"))
-	b, err = ioutil.ReadAll(w.Result().Body)
+	b, err = io.ReadAll(w.Result().Body)
 	require.NoError(t, err)
 	require.Len(t, b, 0)
 }
@@ -246,7 +245,7 @@
 
 	r, err := GetWithContext(context.Background(), m.Client(), "https://example.com/foo")
 	require.NoError(t, err)
-	msg, err := ioutil.ReadAll(r.Body)
+	msg, err := io.ReadAll(r.Body)
 	require.NoError(t, err)
 	assert.Equal(t, content, msg)
 	require.NoError(t, r.Body.Close())
@@ -272,7 +271,7 @@
 
 	r, err := PostWithContext(context.Background(), m.Client(), "https://example.com/foo", mimeType, strings.NewReader(input))
 	require.NoError(t, err)
-	msg, err := ioutil.ReadAll(r.Body)
+	msg, err := io.ReadAll(r.Body)
 	require.NoError(t, err)
 	assert.Equal(t, output, msg)
 	require.NoError(t, r.Body.Close())
diff --git a/go/httputils/progress/progress_test.go b/go/httputils/progress/progress_test.go
index 9c0440a..80d295e 100644
--- a/go/httputils/progress/progress_test.go
+++ b/go/httputils/progress/progress_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"bytes"
-	"io/ioutil"
+	"io"
 	"testing"
 	"time"
 
@@ -109,7 +109,7 @@
 	check(0)
 	resp, err := client.Get("fake-get")
 	require.NoError(t, err)
-	actualRespBytes, err := ioutil.ReadAll(resp.Body)
+	actualRespBytes, err := io.ReadAll(resp.Body)
 	require.Equal(t, mockRespBytes, actualRespBytes)
 	check(int64(len(mockRespBytes)))
 
@@ -124,7 +124,7 @@
 	check(0)
 	resp, err = client.Post("fake-post", "application/json", bytes.NewReader(mockReqBytes))
 	require.NoError(t, err)
-	actualRespBytes, err = ioutil.ReadAll(resp.Body)
+	actualRespBytes, err = io.ReadAll(resp.Body)
 	require.NoError(t, err)
 	require.Equal(t, mockRespBytes, actualRespBytes)
 	check(int64(len(mockReqBytes)))
diff --git a/go/isolate/isolate.go b/go/isolate/isolate.go
index 9d70a82..8c56a07 100644
--- a/go/isolate/isolate.go
+++ b/go/isolate/isolate.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"encoding/json"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 
 	"go.skia.org/infra/go/exec"
@@ -15,7 +15,7 @@
 // Returns the CAS digest.
 func Upload(ctx context.Context, casInstance, baseDir, isolateFile string) (string, error) {
 	// Setup.
-	tmpDir, err := ioutil.TempDir("", "isolate")
+	tmpDir, err := os.MkdirTemp("", "isolate")
 	if err != nil {
 		return "", skerr.Wrapf(err, "failed to create temporary dir")
 	}
@@ -39,7 +39,7 @@
 	}
 
 	// Read the JSON output file and return the hash.
-	b, err := ioutil.ReadFile(jsonOutput)
+	b, err := os.ReadFile(jsonOutput)
 	if err != nil {
 		return "", skerr.Wrap(err)
 	}
diff --git a/go/issues/issues.go b/go/issues/issues.go
index 6cd609f..ad90e52 100644
--- a/go/issues/issues.go
+++ b/go/issues/issues.go
@@ -4,7 +4,7 @@
 	"bytes"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/url"
 
@@ -156,7 +156,7 @@
 		return fmt.Errorf("Failed to retrieve issue tracker response: %s", err)
 	}
 	defer util.Close(resp.Body)
-	msg, err := ioutil.ReadAll(resp.Body)
+	msg, err := io.ReadAll(resp.Body)
 	sklog.Infof("%s\n\nErr: %v", string(msg), err)
 	return nil
 }
diff --git a/go/jsonschema/jsonschema_test.go b/go/jsonschema/jsonschema_test.go
index 574c1bb..53acb37 100644
--- a/go/jsonschema/jsonschema_test.go
+++ b/go/jsonschema/jsonschema_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"testing"
 
@@ -42,7 +42,7 @@
 func TestGenerateSchema_ValidStruct_WritesSchemaFile(t *testing.T) {
 	filename := filepath.Join(t.TempDir(), "schema.json")
 	GenerateSchema(filename, testStruct{})
-	b, err := ioutil.ReadFile(filename)
+	b, err := os.ReadFile(filename)
 	require.NoError(t, err)
 	require.Equal(t, testStructSchema, string(b))
 }
diff --git a/go/kube/clusterconfig/clusterconfig.go b/go/kube/clusterconfig/clusterconfig.go
index c655b33..78627b4 100644
--- a/go/kube/clusterconfig/clusterconfig.go
+++ b/go/kube/clusterconfig/clusterconfig.go
@@ -6,7 +6,6 @@
 import (
 	"context"
 	"encoding/json"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"runtime"
@@ -61,7 +60,7 @@
 		configFilename = filepath.Join(filepath.Dir(filename), "../../../kube/clusters/config.json")
 	}
 
-	b, err := ioutil.ReadFile(configFilename)
+	b, err := os.ReadFile(configFilename)
 	if err != nil {
 		return ret, skerr.Wrap(err)
 	}
diff --git a/go/metadata/metadata.go b/go/metadata/metadata.go
index 16c49dc..2fac1a8 100644
--- a/go/metadata/metadata.go
+++ b/go/metadata/metadata.go
@@ -3,7 +3,7 @@
 import (
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 
 	"go.skia.org/infra/go/httputils"
@@ -92,7 +92,7 @@
 		return "", fmt.Errorf("HTTP response has status %d", resp.StatusCode)
 	}
 	defer util.Close(resp.Body)
-	value, err := ioutil.ReadAll(resp.Body)
+	value, err := io.ReadAll(resp.Body)
 	if err != nil {
 		return "", fmt.Errorf("Failed to read %s from metadata server: %s", url, err)
 	}
diff --git a/go/metrics2/events/events_test.go b/go/metrics2/events/events_test.go
index 52fb1c2..12c8098 100644
--- a/go/metrics2/events/events_test.go
+++ b/go/metrics2/events/events_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"os"
 	"testing"
 	"time"
 
@@ -13,7 +13,7 @@
 
 func TestAggregateMetric(t *testing.T) {
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
@@ -49,7 +49,7 @@
 
 func TestDynamicMetric(t *testing.T) {
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
diff --git a/go/metrics2/testutils/testutils.go b/go/metrics2/testutils/testutils.go
index 78a0a0b..2552ac9 100644
--- a/go/metrics2/testutils/testutils.go
+++ b/go/metrics2/testutils/testutils.go
@@ -2,7 +2,7 @@
 
 import (
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http/httptest"
 	"sort"
 	"strings"
@@ -30,7 +30,7 @@
 	}).ServeHTTP(rw, req)
 	resp := rw.Result()
 	defer util.Close(resp.Body)
-	b, err := ioutil.ReadAll(resp.Body)
+	b, err := io.ReadAll(resp.Body)
 	require.NoError(t, err)
 	// b at this point looks like:
 	// # HELP go_gc_duration_seconds A summary of the GC invocation durations.
diff --git a/go/mockhttpclient/urlmock.go b/go/mockhttpclient/urlmock.go
index a29f2e9..10f8930 100644
--- a/go/mockhttpclient/urlmock.go
+++ b/go/mockhttpclient/urlmock.go
@@ -4,7 +4,6 @@
 	"bytes"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"math"
 	"net/http"
 	"reflect"
@@ -36,18 +35,18 @@
 //	m := NewURLMock()
 //	m.Mock("https://www.google.com", MockGetDialogue([]byte("Here's a response.")))
 //	res, _ := m.Client().Get("https://www.google.com")
-//	respBody, _ := ioutil.ReadAll(res.Body)  // respBody == []byte("Here's a response.")
+//	respBody, _ := io.ReadAll(res.Body)  // respBody == []byte("Here's a response.")
 //
 //	// Mock out a URL to give different responses.
 //	m.MockOnce("https://www.google.com", MockGetDialogue([]byte("hi")))
 //	m.MockOnce("https://www.google.com", MockGetDialogue([]byte("Second response.")))
 //	res1, _ := m.Client().Get("https://www.google.com")
-//	body1, _ := ioutil.ReadAll(res1.Body)  // body1 == []byte("hi")
+//	body1, _ := io.ReadAll(res1.Body)  // body1 == []byte("hi")
 //	res2, _ := m.Client().Get("https://www.google.com")
-//	body2, _ := ioutil.ReadAll(res2.Body)  // body2 == []byte("Second response.")
+//	body2, _ := io.ReadAll(res2.Body)  // body2 == []byte("Second response.")
 //	// Fall back on the value previously set using Mock():
 //	res3, _ := m.Client().Get("https://www.google.com")
-//	body3, _ := ioutil.ReadAll(res3.Body)  // body3 == []byte("Here's a response.")
+//	body3, _ := io.ReadAll(res3.Body)  // body3 == []byte("Here's a response.")
 type URLMock struct {
 	mtx        sync.Mutex
 	mockAlways map[string]MockDialogue
@@ -97,7 +96,7 @@
 	}
 	if md.requestPayload == nil {
 		if r.Body != nil {
-			requestBody, _ := ioutil.ReadAll(r.Body)
+			requestBody, _ := io.ReadAll(r.Body)
 			return nil, fmt.Errorf("No request payload expected, but was %s (%#v) ", string(requestBody), r.Body)
 		}
 	} else {
@@ -105,7 +104,7 @@
 			return nil, fmt.Errorf("Content-Type was wrong, expected %q, but was %q", md.requestType, ct)
 		}
 		defer util.Close(r.Body)
-		requestBody, err := ioutil.ReadAll(r.Body)
+		requestBody, err := io.ReadAll(r.Body)
 		if err != nil {
 			return nil, fmt.Errorf("Error reading request body: %s", err)
 		}
diff --git a/go/mockhttpclient/urlmock_test.go b/go/mockhttpclient/urlmock_test.go
index 880d914..76dfc8b 100644
--- a/go/mockhttpclient/urlmock_test.go
+++ b/go/mockhttpclient/urlmock_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"bytes"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"reflect"
 	"strings"
@@ -30,7 +30,7 @@
 			t.Fatalf("Mock response should not have errored on close. %s", err)
 		}
 	}()
-	b, err := ioutil.ReadAll(resp.Body)
+	b, err := io.ReadAll(resp.Body)
 	if err != nil {
 		t.Errorf("Problem reading response body: %s", err)
 		return nil
diff --git a/go/monorail/v3/monorail.go b/go/monorail/v3/monorail.go
index de6f6bc..4c50088 100644
--- a/go/monorail/v3/monorail.go
+++ b/go/monorail/v3/monorail.go
@@ -5,7 +5,7 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"strings"
 	"time"
@@ -133,7 +133,7 @@
 		return nil, skerr.Wrapf(err, "resp status_code: %d status_text: %s", resp.StatusCode, http.StatusText(resp.StatusCode))
 	}
 
-	b, err := ioutil.ReadAll(resp.Body)
+	b, err := io.ReadAll(resp.Body)
 	if err != nil {
 		return nil, skerr.Fmt("Failed to read response: %s", err)
 	}
diff --git a/go/packages/packages.go b/go/packages/packages.go
index 4ac7c36..4dac886 100644
--- a/go/packages/packages.go
+++ b/go/packages/packages.go
@@ -8,7 +8,6 @@
 	"encoding/json"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"os/exec"
@@ -419,7 +418,7 @@
 		return fmt.Errorf("Failed to retrieve packages file: %s", err)
 	}
 	defer util.Close(resp.Body)
-	f, err := ioutil.TempFile("", "skia-pull")
+	f, err := os.CreateTemp("", "skia-pull")
 	if err != nil {
 		return fmt.Errorf("Failed to create tmp file: %s", err)
 	}
diff --git a/go/rotations/rotations.go b/go/rotations/rotations.go
index 8305b14..9f84fc0 100644
--- a/go/rotations/rotations.go
+++ b/go/rotations/rotations.go
@@ -6,7 +6,7 @@
 import (
 	"bytes"
 	"encoding/json"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"sort"
 
@@ -30,7 +30,7 @@
 		return nil, skerr.Wrap(err)
 	}
 	defer util.Close(resp.Body)
-	body, err := ioutil.ReadAll(resp.Body)
+	body, err := io.ReadAll(resp.Body)
 	if err != nil {
 		return nil, skerr.Wrap(err)
 	}
diff --git a/go/taskname/gen_schema.go b/go/taskname/gen_schema.go
index f751c0e..733e8cb 100644
--- a/go/taskname/gen_schema.go
+++ b/go/taskname/gen_schema.go
@@ -8,7 +8,6 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"runtime"
@@ -72,7 +71,7 @@
 	assetsStr := strings.Join(schemaLines, "")
 	fileContents := []byte(fmt.Sprintf(TMPL, assetsStr, schema.TaskNameSep))
 	targetFile := path.Join(pkgDir, TARGET_FILE)
-	if err := ioutil.WriteFile(targetFile, fileContents, os.ModePerm); err != nil {
+	if err := os.WriteFile(targetFile, fileContents, os.ModePerm); err != nil {
 		sklog.Fatal(err)
 	}
 	if _, err := exec.RunCwd(context.Background(), ".", "gofmt", "-s", "-w", targetFile); err != nil {
diff --git a/go/test2json/testutils.go b/go/test2json/testutils.go
index 8f4ea86..9b196ef 100644
--- a/go/test2json/testutils.go
+++ b/go/test2json/testutils.go
@@ -2,7 +2,6 @@
 
 import (
 	"context"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -75,7 +74,7 @@
 // sequence of Events from above.
 func SetupTest(content TestContent) (tmpDir string, cleanup func(), err error) {
 	// Create a temporary dir with a go package to test.
-	tmpDir, err = ioutil.TempDir("", "")
+	tmpDir, err = os.MkdirTemp("", "")
 	if err != nil {
 		return
 	}
@@ -93,7 +92,7 @@
 	if err != nil {
 		return
 	}
-	err = ioutil.WriteFile(filepath.Join(pkgPath, "test2json_test.go"), []byte(content), os.ModePerm)
+	err = os.WriteFile(filepath.Join(pkgPath, "test2json_test.go"), []byte(content), os.ModePerm)
 	if err != nil {
 		return
 	}
diff --git a/go/testutils/testutils.go b/go/testutils/testutils.go
index 74ea6f1..4e37838 100644
--- a/go/testutils/testutils.go
+++ b/go/testutils/testutils.go
@@ -7,7 +7,6 @@
 	"encoding/json"
 	"errors"
 	"io"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"runtime"
@@ -59,7 +58,7 @@
 // slice of bytes.
 func ReadFileBytes(t sktest.TestingT, filename string) []byte {
 	f := GetReader(t, filename)
-	b, err := ioutil.ReadAll(f)
+	b, err := io.ReadAll(f)
 	require.NoError(t, err, "Could not read %s: %v", filename)
 	require.NoError(t, f.Close())
 	return b
@@ -91,7 +90,7 @@
 // WriteFile writes the given contents to the given file path, reporting any
 // error.
 func WriteFile(t sktest.TestingT, filename, contents string) {
-	require.NoErrorf(t, ioutil.WriteFile(filename, []byte(contents), os.ModePerm), "Unable to write to file %s", filename)
+	require.NoErrorf(t, os.WriteFile(filename, []byte(contents), os.ModePerm), "Unable to write to file %s", filename)
 }
 
 // AssertCloses takes an ioutil.Closer and asserts that it closes. E.g.:
@@ -176,7 +175,7 @@
 //
 // See https://docs.bazel.build/versions/master/test-encyclopedia.html#initial-conditions.
 func SetUpFakeHomeDir(t sktest.TestingT, tempDirPattern string) {
-	fakeHome, err := ioutil.TempDir("", tempDirPattern)
+	fakeHome, err := os.MkdirTemp("", tempDirPattern)
 	require.NoError(t, err)
 	oldHome := os.Getenv("HOME")
 	require.NoError(t, os.Setenv("HOME", fakeHome))
diff --git a/go/travisci/travisci.go b/go/travisci/travisci.go
index 33aec5d..a0a1d08 100644
--- a/go/travisci/travisci.go
+++ b/go/travisci/travisci.go
@@ -10,7 +10,7 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/url"
 	"strconv"
@@ -112,7 +112,7 @@
 		return fmt.Errorf("Error retrieving %s: %d %s", getURL, resp.StatusCode, resp.Status)
 	}
 	defer util.Close(resp.Body)
-	body, err := ioutil.ReadAll(resp.Body)
+	body, err := io.ReadAll(resp.Body)
 	if err != nil {
 		return fmt.Errorf("Could not read response body: %s", err)
 	}
diff --git a/go/util/util.go b/go/util/util.go
index 6f57dc3..0482c34 100644
--- a/go/util/util.go
+++ b/go/util/util.go
@@ -8,7 +8,6 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"reflect"
@@ -634,7 +633,7 @@
 	}
 
 	tempBase := filepath.Base(file)
-	f, err := ioutil.TempFile(dir, tempBase)
+	f, err := os.CreateTemp(dir, tempBase)
 	if err != nil {
 		return skerr.Wrapf(err, "creating temporary file %q in WithWriteFile for %q", tempBase, file)
 	}
diff --git a/go/util/util_test.go b/go/util/util_test.go
index b1400a4..624380f 100644
--- a/go/util/util_test.go
+++ b/go/util/util_test.go
@@ -164,7 +164,7 @@
 }
 
 func TestIsDirEmpty(t *testing.T) {
-	d, err := ioutil.TempDir(os.TempDir(), "test_empty")
+	d, err := os.MkdirTemp(os.TempDir(), "test_empty")
 	require.NoError(t, err)
 	defer RemoveAll(d)
 
@@ -174,7 +174,7 @@
 	require.True(t, empty)
 
 	// Add a file in the directory.
-	f, err := ioutil.TempFile(d, "test_file")
+	f, err := os.CreateTemp(d, "test_file")
 	require.NoError(t, err)
 	_, err = f.WriteString("testing")
 	Close(f)
@@ -247,7 +247,7 @@
 }
 
 func TestWithWriteFile(t *testing.T) {
-	tmp, err := ioutil.TempDir("", "whatever")
+	tmp, err := os.MkdirTemp("", "whatever")
 	require.NoError(t, err)
 
 	targetFile := filepath.Join(tmp, "this", "is", "in", "a", "subdir.txt")
@@ -258,7 +258,7 @@
 	require.NoError(t, err)
 	require.FileExists(t, targetFile)
 
-	b, err := ioutil.ReadFile(targetFile)
+	b, err := os.ReadFile(targetFile)
 	require.NoError(t, err)
 	assert.Equal(t, "some words", string(b))
 }
@@ -553,7 +553,7 @@
 
 func TestCopyFile(t *testing.T) {
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer func() {
 		require.NoError(t, os.RemoveAll(tmp))
@@ -566,7 +566,7 @@
 		src := filepath.Join(tmp, fmt.Sprintf("src-%d", fileNum))
 		dst := filepath.Join(tmp, fmt.Sprintf("dst-%d", fileNum))
 		fileNum++
-		require.NoError(t, ioutil.WriteFile(src, contents, mode))
+		require.NoError(t, os.WriteFile(src, contents, mode))
 		// Set the mode again to work around umask.
 		require.NoError(t, os.Chmod(src, mode))
 		srcStat, err := os.Stat(src)
@@ -582,7 +582,7 @@
 		dstStat, err := os.Stat(dst)
 		require.NoError(t, err)
 		require.Equal(t, srcStat.Mode(), dstStat.Mode())
-		resultContents, err := ioutil.ReadFile(dst)
+		resultContents, err := os.ReadFile(dst)
 		require.NoError(t, err)
 		require.Equal(t, contents, resultContents)
 	}
diff --git a/go/util/zip/zip.go b/go/util/zip/zip.go
index ee5c09e..484784b 100644
--- a/go/util/zip/zip.go
+++ b/go/util/zip/zip.go
@@ -4,7 +4,6 @@
 	"archive/zip"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 )
@@ -43,11 +42,11 @@
 				return err
 			}
 		} else {
-			contents, err := ioutil.ReadAll(r)
+			contents, err := io.ReadAll(r)
 			if err != nil {
 				return err
 			}
-			return ioutil.WriteFile(path, contents, f.Mode())
+			return os.WriteFile(path, contents, f.Mode())
 		}
 		return nil
 	}
diff --git a/go/util/zip/zip_test.go b/go/util/zip/zip_test.go
index d4fcf7d..8057fb6 100644
--- a/go/util/zip/zip_test.go
+++ b/go/util/zip/zip_test.go
@@ -1,7 +1,6 @@
 package zip
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -11,7 +10,7 @@
 )
 
 func createFile(dir, prefix, content string, t *testing.T) string {
-	f, err := ioutil.TempFile(dir, prefix)
+	f, err := os.CreateTemp(dir, prefix)
 	require.NoError(t, err)
 	_, err = f.WriteString(content)
 	require.NoError(t, err)
@@ -20,7 +19,7 @@
 }
 
 func assertFileExists(dir, path, content string, t *testing.T) {
-	c, err := ioutil.ReadFile(filepath.Join(dir, filepath.Base(path)))
+	c, err := os.ReadFile(filepath.Join(dir, filepath.Base(path)))
 	require.NoError(t, err)
 	require.Equal(t, content, string(c))
 }
@@ -28,7 +27,7 @@
 func TestZipE2E(t *testing.T) {
 
 	// Create a directory in temp.
-	targetDir, err := ioutil.TempDir("", "zip_test")
+	targetDir, err := os.MkdirTemp("", "zip_test")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, targetDir)
 
@@ -37,16 +36,16 @@
 	f1 := createFile(targetDir, "temp1", "testing1", t)
 	f2 := createFile(targetDir, "temp2", "testing2", t)
 	// Create subdir.
-	subDir, err := ioutil.TempDir(targetDir, "zip_test")
+	subDir, err := os.MkdirTemp(targetDir, "zip_test")
 	require.NoError(t, err)
 	// Create one file in subdir.
 	f3 := createFile(subDir, "temp3", "testing3", t)
 	// Create an empty subdir.
-	emptySubDir, err := ioutil.TempDir(targetDir, "zip_test")
+	emptySubDir, err := os.MkdirTemp(targetDir, "zip_test")
 	require.NoError(t, err)
 
 	// Zip the directory.
-	outputDir, err := ioutil.TempDir("", "zip_location")
+	outputDir, err := os.MkdirTemp("", "zip_location")
 	defer testutils.RemoveAll(t, outputDir)
 	zipPath := filepath.Join(outputDir, "test.zip")
 	err = Directory(zipPath, targetDir)
diff --git a/go/vcsinfo/bt_vcs/bt_vcs_test.go b/go/vcsinfo/bt_vcs/bt_vcs_test.go
index efb714a..698586f 100644
--- a/go/vcsinfo/bt_vcs/bt_vcs_test.go
+++ b/go/vcsinfo/bt_vcs/bt_vcs_test.go
@@ -2,8 +2,8 @@
 
 import (
 	"context"
-	"io/ioutil"
 	"math"
+	"os"
 	"testing"
 	"time"
 
@@ -166,7 +166,7 @@
 // setupVCSLocalRepo loads the test repo into a new GitStore and returns an instance of vcsinfo.VCS.
 func setupVCSLocalRepo(t *testing.T, branch string) (context.Context, vcsinfo.VCS, gitstore.GitStore, func()) {
 	repoDir, cleanup := vcs_testutils.InitTempRepo(t)
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	ctx := cipd_git.UseGitFinder(context.Background())
 	_, _, btgs := gs_testutils.SetupAndLoadBTGitStore(t, ctx, wd, "file://"+repoDir, true)
diff --git a/go/vcsinfo/testutils/repo.go b/go/vcsinfo/testutils/repo.go
index af948ad..163484c 100644
--- a/go/vcsinfo/testutils/repo.go
+++ b/go/vcsinfo/testutils/repo.go
@@ -1,7 +1,6 @@
 package testutils
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -26,7 +25,7 @@
 // given zip file path. Unzips to a temporary directory which is stored in
 // tempRepo.Dir.
 func newTempRepoFrom(zipfile string) *tempRepo {
-	tmpdir, err := ioutil.TempDir("", "skiaperf")
+	tmpdir, err := os.MkdirTemp("", "skiaperf")
 	if err != nil {
 		sklog.Fatal("Failed to create testing Git repo:", err)
 	}
diff --git a/go/vfs/local.go b/go/vfs/local.go
index be2484e..0a17be5 100644
--- a/go/vfs/local.go
+++ b/go/vfs/local.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"io/fs"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -135,7 +134,7 @@
 // TempDir returns a FS which is rooted in a temporary directory. Calling Close
 // causes the directory to be deleted.
 func TempDir(_ context.Context, dir, prefix string) (*TempDirFS, error) {
-	tmp, err := ioutil.TempDir(dir, prefix)
+	tmp, err := os.MkdirTemp(dir, prefix)
 	if err != nil {
 		return nil, skerr.Wrap(err)
 	}
diff --git a/go/vfs/shared_tests/shared_tests.go b/go/vfs/shared_tests/shared_tests.go
index 372437e..0c65f0d 100644
--- a/go/vfs/shared_tests/shared_tests.go
+++ b/go/vfs/shared_tests/shared_tests.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"io"
 	"os"
 	"path"
 	"path/filepath"
@@ -72,7 +72,7 @@
 	// Read.
 	rootFile, err := fs.Open(ctx, FakeFileName)
 	require.NoError(t, err)
-	rootFileContents, err := ioutil.ReadAll(vfs.WithContext(ctx, rootFile))
+	rootFileContents, err := io.ReadAll(vfs.WithContext(ctx, rootFile))
 	require.NoError(t, err)
 	require.Equal(t, []byte(FakeContents), rootFileContents)
 	st, err := rootFile.Stat(ctx)
@@ -103,8 +103,8 @@
 func MakeTestFiles(t sktest.TestingT) string {
 	tmp := t.TempDir()
 	require.NoError(t, os.MkdirAll(filepath.Join(tmp, "subdir"), os.ModePerm))
-	require.NoError(t, ioutil.WriteFile(filepath.Join(tmp, FakeFileName), FakeContents, os.ModePerm))
-	require.NoError(t, ioutil.WriteFile(filepath.Join(tmp, "subdir", "subDirFile"), []byte("subDirFile contents"), os.ModePerm))
+	require.NoError(t, os.WriteFile(filepath.Join(tmp, FakeFileName), FakeContents, os.ModePerm))
+	require.NoError(t, os.WriteFile(filepath.Join(tmp, "subdir", "subDirFile"), []byte("subDirFile contents"), os.ModePerm))
 	return tmp
 }
 
diff --git a/go/vfs/shared_tests/vfs_test.go b/go/vfs/shared_tests/vfs_test.go
index 9625283..6114eb9 100644
--- a/go/vfs/shared_tests/vfs_test.go
+++ b/go/vfs/shared_tests/vfs_test.go
@@ -54,7 +54,7 @@
 	fs.On("Open", ctx, name).Return(f, nil)
 	contents := []uint8("hello world")
 	// Note: this only works because our input is smaller than the buffer size
-	// used by ioutil.ReadAll.
+	// used by io.ReadAll.
 	f.On("Read", ctx, mock.AnythingOfType("[]uint8")).Run(func(args mock.Arguments) {
 		arg := args.Get(1).([]uint8)
 		copy(arg, contents)
diff --git a/go/vfs/vfs.go b/go/vfs/vfs.go
index 3c4c553..90c448f 100644
--- a/go/vfs/vfs.go
+++ b/go/vfs/vfs.go
@@ -9,8 +9,8 @@
 
 import (
 	"context"
+	"io"
 	"io/fs"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -88,7 +88,7 @@
 	}
 }
 
-// ReadFile is analogous to ioutil.ReadFile.
+// ReadFile is analogous to os.ReadFile.
 func ReadFile(ctx context.Context, fs FS, path string) (rv []byte, rvErr error) {
 	f, err := fs.Open(ctx, path)
 	if err != nil {
@@ -101,7 +101,7 @@
 		}
 	}()
 	wrapFile := WithContext(ctx, f)
-	return ioutil.ReadAll(wrapFile)
+	return io.ReadAll(wrapFile)
 }
 
 // ReadDir is analogous to ioutil.ReadDir.
diff --git a/go/webhook/webhook.go b/go/webhook/webhook.go
index 1eec609..d59c5c4 100644
--- a/go/webhook/webhook.go
+++ b/go/webhook/webhook.go
@@ -10,8 +10,9 @@
 	"crypto/sha512"
 	"encoding/base64"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
+	"os"
 
 	"go.skia.org/infra/go/metadata"
 	"go.skia.org/infra/go/sklog"
@@ -71,7 +72,7 @@
 // InitRequestSaltFromFile reads requestSalt from the given file and returns any error encountered.
 // Should be called once at startup.
 func InitRequestSaltFromFile(filename string) error {
-	saltBase64Bytes, err := ioutil.ReadFile(filename)
+	saltBase64Bytes, err := os.ReadFile(filename)
 	if err != nil {
 		return fmt.Errorf("Could not read the webhook request salt file: %s", err)
 	}
@@ -125,7 +126,7 @@
 // In all cases, closes r.Body.
 func AuthenticateRequest(r *http.Request) ([]byte, error) {
 	defer skutil.Close(r.Body)
-	data, err := ioutil.ReadAll(r.Body)
+	data, err := io.ReadAll(r.Body)
 	if err != nil {
 		return nil, err
 	}
diff --git a/go/webhook/webhook_test.go b/go/webhook/webhook_test.go
index 968f4f2..bdd8a27 100644
--- a/go/webhook/webhook_test.go
+++ b/go/webhook/webhook_test.go
@@ -2,9 +2,9 @@
 
 import (
 	"bytes"
-	"io/ioutil"
 	"net/http"
 	"net/url"
+	"os"
 	"testing"
 
 	expect "github.com/stretchr/testify/assert"
@@ -30,7 +30,7 @@
 }
 
 func TestMustInitRequestSaltFromFileSuccess(t *testing.T) {
-	f, err := ioutil.TempFile("", "webhook_test_salt")
+	f, err := os.CreateTemp("", "webhook_test_salt")
 	require.NoError(t, err)
 	defer util.Remove(f.Name())
 	_, err = f.WriteString(TEST_SALT_BASE64)
diff --git a/gold-client/cmd/goldctl/cmd_auth_test.go b/gold-client/cmd/goldctl/cmd_auth_test.go
index ec3d033..5f3cf9d 100644
--- a/gold-client/cmd/goldctl/cmd_auth_test.go
+++ b/gold-client/cmd/goldctl/cmd_auth_test.go
@@ -3,7 +3,7 @@
 import (
 	"bytes"
 	"context"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 	"testing"
@@ -29,7 +29,7 @@
 	logs := output.String()
 	assert.Contains(t, logs, `Falling back to gsutil implementation
 This should not be used in production.`)
-	b, err := ioutil.ReadFile(filepath.Join(workDir, "auth_opt.json"))
+	b, err := os.ReadFile(filepath.Join(workDir, "auth_opt.json"))
 	require.NoError(t, err)
 	assert.Equal(t, `{"Luci":false,"ServiceAccount":"","GSUtil":true,"NoAuth":false}`, strings.TrimSpace(string(b)))
 }
@@ -49,7 +49,7 @@
 		env.Auth(ctx)
 	})
 	exit.AssertWasCalledWithCode(t, 0, output.String())
-	b, err := ioutil.ReadFile(filepath.Join(workDir, "auth_opt.json"))
+	b, err := os.ReadFile(filepath.Join(workDir, "auth_opt.json"))
 	require.NoError(t, err)
 	assert.Equal(t, `{"Luci":false,"ServiceAccount":"","GSUtil":false,"NoAuth":true}`, strings.TrimSpace(string(b)))
 }
diff --git a/gold-client/cmd/goldctl/cmd_diff_test.go b/gold-client/cmd/goldctl/cmd_diff_test.go
index 2f2953f..87a7897 100644
--- a/gold-client/cmd/goldctl/cmd_diff_test.go
+++ b/gold-client/cmd/goldctl/cmd_diff_test.go
@@ -2,8 +2,8 @@
 
 import (
 	"encoding/json"
-	"io/ioutil"
 	"net/http"
+	"os"
 	"path/filepath"
 	"testing"
 
@@ -29,9 +29,9 @@
 	mh.On("Get", "https://my-instance-gold.skia.org/json/v2/digests?grouping=name%3Dpixel-tests%26source_type%3Dmy_corpus").Return(
 		httpResponse(string(j), "200 OK", http.StatusOK), nil)
 
-	a05Bytes, err := ioutil.ReadFile(filepath.Join(td, a05Digest+".png"))
+	a05Bytes, err := os.ReadFile(filepath.Join(td, a05Digest+".png"))
 	require.NoError(t, err)
-	a09Bytes, err := ioutil.ReadFile(filepath.Join(td, a09Digest+".png"))
+	a09Bytes, err := os.ReadFile(filepath.Join(td, a09Digest+".png"))
 	require.NoError(t, err)
 	mi := &mocks.ImageDownloader{}
 	mi.On("DownloadImage", testutils.AnyContext, "https://my-instance-gold.skia.org", types.Digest(a05Digest)).Return(a05Bytes, nil)
@@ -70,9 +70,9 @@
 	mh.On("Get", "https://my-instance-gold.skia.org/json/v2/digests?grouping=color_config%3DRGBA8888%26name%3Dpixel-tests%26source_type%3Dmy_corpus").Return(
 		httpResponse(string(j), "200 OK", http.StatusOK), nil)
 
-	a05Bytes, err := ioutil.ReadFile(filepath.Join(td, a05Digest+".png"))
+	a05Bytes, err := os.ReadFile(filepath.Join(td, a05Digest+".png"))
 	require.NoError(t, err)
-	a09Bytes, err := ioutil.ReadFile(filepath.Join(td, a09Digest+".png"))
+	a09Bytes, err := os.ReadFile(filepath.Join(td, a09Digest+".png"))
 	require.NoError(t, err)
 	mi := &mocks.ImageDownloader{}
 	mi.On("DownloadImage", testutils.AnyContext, "https://my-instance-gold.skia.org", types.Digest(a05Digest)).Return(a05Bytes, nil)
diff --git a/gold-client/cmd/goldctl/cmd_imgtest.go b/gold-client/cmd/goldctl/cmd_imgtest.go
index 6aede4c..31c0b39 100644
--- a/gold-client/cmd/goldctl/cmd_imgtest.go
+++ b/gold-client/cmd/goldctl/cmd_imgtest.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"encoding/json"
-	"io/ioutil"
 	"os"
 	"strings"
 
@@ -377,7 +376,7 @@
 	retval := map[string]string{}
 
 	if filename != "" {
-		jsonBytes, err := ioutil.ReadFile(filename)
+		jsonBytes, err := os.ReadFile(filename)
 		if err != nil {
 			logErrf(ctx, "Could not read file %s: %s", filename, err)
 			exitProcess(ctx, 1)
diff --git a/gold-client/cmd/goldctl/cmd_imgtest_test.go b/gold-client/cmd/goldctl/cmd_imgtest_test.go
index fa91961..e64fddf 100644
--- a/gold-client/cmd/goldctl/cmd_imgtest_test.go
+++ b/gold-client/cmd/goldctl/cmd_imgtest_test.go
@@ -7,7 +7,7 @@
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"os"
 	"path/filepath"
@@ -56,7 +56,7 @@
 	setupAuthWithGSUtil(t, workDir)
 
 	keysFile := filepath.Join(workDir, "keys.json")
-	require.NoError(t, ioutil.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
+	require.NoError(t, os.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
 
 	mh := mockRPCResponses("https://my-instance-gold.skia.org").Positive("pixel-tests", blankDigest).
 		Negative("other-test", blankDigest).
@@ -78,7 +78,7 @@
 	})
 	exit.AssertWasCalledWithCode(t, 0, output.String())
 
-	b, err := ioutil.ReadFile(filepath.Join(workDir, "result-state.json"))
+	b, err := os.ReadFile(filepath.Join(workDir, "result-state.json"))
 	require.NoError(t, err)
 	resultState := string(b)
 	assert.Contains(t, resultState, `"key":{"os":"Android","source_type":"my_corpus"}`)
@@ -93,7 +93,7 @@
 	setupAuthWithGSUtil(t, workDir)
 
 	keysFile := filepath.Join(workDir, "keys.json")
-	require.NoError(t, ioutil.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
+	require.NoError(t, os.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
 
 	mh := mockRPCResponses("https://my-instance-gold.skia.org").Positive("pixel-tests", blankDigest).
 		Negative("other-test", blankDigest).
@@ -116,7 +116,7 @@
 	})
 	exit.AssertWasCalledWithCode(t, 0, output.String())
 
-	b, err := ioutil.ReadFile(filepath.Join(workDir, "result-state.json"))
+	b, err := os.ReadFile(filepath.Join(workDir, "result-state.json"))
 	require.NoError(t, err)
 	resultState := string(b)
 	assert.Contains(t, resultState, `"key":{"os":"Android","source_type":"my_corpus"}`)
@@ -131,7 +131,7 @@
 	setupAuthWithGSUtil(t, workDir)
 
 	keysFile := filepath.Join(workDir, "keys.json")
-	require.NoError(t, ioutil.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
+	require.NoError(t, os.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
 
 	mh := mockRPCResponses("https://my-instance-gold.skia.org").Positive("pixel-tests", blankDigest).
 		Negative("other-test", blankDigest).
@@ -157,7 +157,7 @@
 	})
 	exit.AssertWasCalledWithCode(t, 0, output.String())
 
-	b, err := ioutil.ReadFile(filepath.Join(workDir, "result-state.json"))
+	b, err := os.ReadFile(filepath.Join(workDir, "result-state.json"))
 	require.NoError(t, err)
 	resultState := string(b)
 	assert.Contains(t, resultState, `"key":{"os":"Android","source_type":"my_corpus"}`)
@@ -172,7 +172,7 @@
 	setupAuthWithGSUtil(t, workDir)
 
 	keysFile := filepath.Join(workDir, "keys.json")
-	require.NoError(t, ioutil.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
+	require.NoError(t, os.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
 
 	// Call imgtest init with the following flags. We expect it to fail because we need to provide
 	// a commit or CL info
@@ -198,7 +198,7 @@
 	setupAuthWithGSUtil(t, workDir)
 
 	keysFile := filepath.Join(workDir, "keys.json")
-	require.NoError(t, ioutil.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
+	require.NoError(t, os.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
 
 	mh := mockRPCResponses("https://my-instance-gold.skia.org").
 		Known("11111111111111111111111111111111").Build()
@@ -226,7 +226,7 @@
 	setupAuthWithGSUtil(t, workDir)
 
 	keysFile := filepath.Join(workDir, "keys.json")
-	require.NoError(t, ioutil.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
+	require.NoError(t, os.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
 
 	mh := mockRPCResponses("https://my-instance-gold.skia.org").
 		Known("11111111111111111111111111111111").Build()
@@ -325,7 +325,7 @@
 	assert.Contains(t, logs, `Untriaged or negative image: https://my-instance-gold.skia.org/detail?grouping=name%3Dpixel-tests%26source_type%3Dmy_corpus&digest=00000000000000000000000000000000`)
 	assert.Contains(t, logs, `Test: pixel-tests FAIL`)
 
-	fb, err := ioutil.ReadFile(filepath.Join(workDir, "failures.txt"))
+	fb, err := os.ReadFile(filepath.Join(workDir, "failures.txt"))
 	require.NoError(t, err)
 	assert.Contains(t, string(fb), "https://my-instance-gold.skia.org/detail?grouping=name%3Dpixel-tests%26source_type%3Dmy_corpus&digest=00000000000000000000000000000000")
 }
@@ -455,7 +455,7 @@
 	assert.Contains(t, logs, `Untriaged or negative image: https://my-custom-gold-url.example.com/detail?grouping=name%3Dpixel-tests%26source_type%3Dmy_corpus&digest=00000000000000000000000000000000`)
 	assert.Contains(t, logs, `Test: pixel-tests FAIL`)
 
-	fb, err := ioutil.ReadFile(filepath.Join(workDir, "failures.txt"))
+	fb, err := os.ReadFile(filepath.Join(workDir, "failures.txt"))
 	require.NoError(t, err)
 	assert.Contains(t, string(fb), "https://my-custom-gold-url.example.com/detail?grouping=name%3Dpixel-tests%26source_type%3Dmy_corpus&digest=00000000000000000000000000000000")
 }
@@ -628,7 +628,7 @@
 	td := testutils.TestDataDir(t)
 
 	keysFile := filepath.Join(workDir, "keys.json")
-	require.NoError(t, ioutil.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
+	require.NoError(t, os.WriteFile(keysFile, []byte(`{"os": "Android"}`), 0644))
 
 	mh := mockRPCResponses("https://my-instance-gold.skia.org").Positive("pixel-tests", blankDigest).Build()
 
@@ -882,7 +882,7 @@
 			"device": "bullhead", "name": "pixel-tests", "source_type": "my-instance",
 		}).Build()
 
-	a01Bytes, err := ioutil.ReadFile(filepath.Join(td, a01Digest+".png"))
+	a01Bytes, err := os.ReadFile(filepath.Join(td, a01Digest+".png"))
 	require.NoError(t, err)
 	mi := &mocks.ImageDownloader{}
 	mi.On("DownloadImage", testutils.AnyContext, "https://my-instance-gold.skia.org", types.Digest(a01Digest)).Return(a01Bytes, nil)
@@ -920,7 +920,7 @@
 			"device": "bullhead", "name": "pixel-tests", "source_type": "my-instance",
 		}).BuildForCL("gerritHub", "cl_1234")
 
-	a01Bytes, err := ioutil.ReadFile(filepath.Join(td, a01Digest+".png"))
+	a01Bytes, err := os.ReadFile(filepath.Join(td, a01Digest+".png"))
 	require.NoError(t, err)
 	mi := &mocks.ImageDownloader{}
 	mi.On("DownloadImage", testutils.AnyContext, "https://my-instance-gold.skia.org", types.Digest(a01Digest)).Return(a01Bytes, nil)
@@ -1086,13 +1086,13 @@
 	mh := mockRPCResponses("https://my-instance-gold.skia.org").Build()
 	resp, err := mh.Get("https://my-instance-gold.skia.org/json/v1/hashes")
 	require.NoError(t, err)
-	b, err := ioutil.ReadAll(resp.Body)
+	b, err := io.ReadAll(resp.Body)
 	require.NoError(t, err)
 	assert.Equal(t, "", string(b))
 
 	resp, err = mh.Get("https://my-instance-gold.skia.org/json/v2/expectations")
 	require.NoError(t, err)
-	b, err = ioutil.ReadAll(resp.Body)
+	b, err = io.ReadAll(resp.Body)
 	require.NoError(t, err)
 	assert.Equal(t, `{}`, string(b))
 }
@@ -1109,7 +1109,7 @@
 		Build()
 	resp, err := mh.Get("http://my-custom-url.example.com/json/v1/hashes")
 	require.NoError(t, err)
-	b, err := ioutil.ReadAll(resp.Body)
+	b, err := io.ReadAll(resp.Body)
 	require.NoError(t, err)
 	assert.Equal(t, `first_digest
 second_digest
@@ -1119,7 +1119,7 @@
 
 	resp, err = mh.Get("http://my-custom-url.example.com/json/v2/expectations")
 	require.NoError(t, err)
-	b, err = ioutil.ReadAll(resp.Body)
+	b, err = io.ReadAll(resp.Body)
 	require.NoError(t, err)
 	assert.Equal(t, `{"primary":{"alpha test":{"fourth_digest":"negative","second_digest":"positive"},"beta test":{"third_digest":"positive"}}}`, string(b))
 
@@ -1128,7 +1128,7 @@
 	require.Equal(t, expectedTraceID, hex.EncodeToString(tb))
 	resp, err = mh.Get("http://my-custom-url.example.com/json/v2/latestpositivedigest/" + expectedTraceID)
 	require.NoError(t, err)
-	b, err = ioutil.ReadAll(resp.Body)
+	b, err = io.ReadAll(resp.Body)
 	require.NoError(t, err)
 	assert.Equal(t, `{"digest":"third_digest"}`, string(b))
 }
diff --git a/gold-client/cmd/goldctl/cmd_match.go b/gold-client/cmd/goldctl/cmd_match.go
index e733178..aa1a791 100644
--- a/gold-client/cmd/goldctl/cmd_match.go
+++ b/gold-client/cmd/goldctl/cmd_match.go
@@ -6,7 +6,7 @@
 	"image"
 	"image/png"
 	"io"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"strings"
 
@@ -103,7 +103,7 @@
 // loadPng loads a PNG image from disk.
 func loadPng(fileName string) (image.Image, error) {
 	// Load the image and save the bytes because we need to return them.
-	imgBytes, err := ioutil.ReadFile(fileName)
+	imgBytes, err := os.ReadFile(fileName)
 	if err != nil {
 		return nil, skerr.Wrapf(err, "loading file %s", fileName)
 	}
@@ -165,7 +165,7 @@
 // temporary directory and prints out the resulting paths. It also prints out the stats reported by
 // the embedded fuzzy.Matcher.
 func printOutSobelDebugInfo(ctx context.Context, matcher *sobel.Matcher) error {
-	tempDir, err := ioutil.TempDir("", "goldctl-*")
+	tempDir, err := os.MkdirTemp("", "goldctl-*")
 	if err != nil {
 		return skerr.Wrap(err)
 	}
diff --git a/gold-client/cmd/goldctl/cmd_whoami_test.go b/gold-client/cmd/goldctl/cmd_whoami_test.go
index b0a598d..623ce4b 100644
--- a/gold-client/cmd/goldctl/cmd_whoami_test.go
+++ b/gold-client/cmd/goldctl/cmd_whoami_test.go
@@ -3,7 +3,7 @@
 import (
 	"bytes"
 	"context"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"strings"
 	"testing"
@@ -66,7 +66,7 @@
 func httpResponse(body, status string, statusCode int) func(string) *http.Response {
 	return func(_ string) *http.Response {
 		return &http.Response{
-			Body:       ioutil.NopCloser(strings.NewReader(body)),
+			Body:       io.NopCloser(strings.NewReader(body)),
 			Status:     status,
 			StatusCode: statusCode,
 		}
diff --git a/gold-client/go/gcsuploader/gcsuploader.go b/gold-client/go/gcsuploader/gcsuploader.go
index ea04fac..5014f77 100644
--- a/gold-client/go/gcsuploader/gcsuploader.go
+++ b/gold-client/go/gcsuploader/gcsuploader.go
@@ -5,8 +5,8 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net/http"
+	"os"
 	"runtime"
 	"strings"
 	"time"
@@ -51,7 +51,7 @@
 		return skerr.Wrapf(err, "could not marshal to JSON before uploading")
 	}
 
-	if err := ioutil.WriteFile(tempFileName, jsonBytes, 0644); err != nil {
+	if err := os.WriteFile(tempFileName, jsonBytes, 0644); err != nil {
 		return skerr.Wrapf(err, "saving json to %s", tempFileName)
 	}
 
@@ -121,7 +121,7 @@
 		}
 
 		var err error
-		data, err = ioutil.ReadFile(fallbackSrc)
+		data, err = os.ReadFile(fallbackSrc)
 		if err != nil {
 			return skerr.Wrapf(err, "reading file %s", fallbackSrc)
 		}
diff --git a/gold-client/go/gcsuploader/gcsuploader_manual_test.go b/gold-client/go/gcsuploader/gcsuploader_manual_test.go
index 4156da3..b527ddf 100644
--- a/gold-client/go/gcsuploader/gcsuploader_manual_test.go
+++ b/gold-client/go/gcsuploader/gcsuploader_manual_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"io"
 	"math/rand"
 	"path"
 	"strconv"
@@ -84,7 +84,7 @@
 	r, err := c.Bucket(testBucket).Object(file).NewReader(ctx)
 	require.NoError(t, err)
 	defer util.Close(r)
-	b, err := ioutil.ReadAll(r)
+	b, err := io.ReadAll(r)
 	require.NoError(t, err)
 	return b
 }
diff --git a/gold-client/go/gcsuploader/gcsuploader_test.go b/gold-client/go/gcsuploader/gcsuploader_test.go
index 5953c94..1c0a52e 100644
--- a/gold-client/go/gcsuploader/gcsuploader_test.go
+++ b/gold-client/go/gcsuploader/gcsuploader_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"testing"
 
@@ -44,7 +44,7 @@
 	expectedCmd := fmt.Sprintf("gsutil cp %s gs://gs://bucket/foo/bar.json", tf)
 	assert.Equal(t, expectedCmd, exec.DebugString(cc.Commands()[0]))
 
-	b, err := ioutil.ReadFile(tf)
+	b, err := os.ReadFile(tf)
 	require.NoError(t, err)
 	assert.Equal(t, `{"One":"alpha"}`, string(b))
 }
diff --git a/gold-client/go/goldclient/common.go b/gold-client/go/goldclient/common.go
index da7cd9e..e30b5d2 100644
--- a/gold-client/go/goldclient/common.go
+++ b/gold-client/go/goldclient/common.go
@@ -5,7 +5,6 @@
 	"encoding/json"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"time"
 
@@ -48,7 +47,7 @@
 				fmt.Printf("Warning while closing HTTP response for %s: %s", url, err)
 			}
 		}()
-		returnBytes, err = ioutil.ReadAll(resp.Body)
+		returnBytes, err = io.ReadAll(resp.Body)
 		if err != nil {
 			return logAndReturn(skerr.Wrapf(err, "reading body from GET %s", url))
 		}
@@ -73,7 +72,7 @@
 		return nil, skerr.Fmt("POST %s resulted in a %d: %s", url, resp.StatusCode, resp.Status)
 	}
 
-	bytes, err := ioutil.ReadAll(resp.Body)
+	bytes, err := io.ReadAll(resp.Body)
 	if err != nil {
 		return nil, skerr.Fmt("error reading body from POST %s: %s", url, err)
 	}
diff --git a/gold-client/go/goldclient/common_test.go b/gold-client/go/goldclient/common_test.go
index bf323a8..0a0f1b8 100644
--- a/gold-client/go/goldclient/common_test.go
+++ b/gold-client/go/goldclient/common_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"errors"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"strings"
 	"testing"
@@ -107,7 +107,7 @@
 
 func httpResponse(body, status string, statusCode int) *http.Response {
 	return &http.Response{
-		Body:       ioutil.NopCloser(strings.NewReader(body)),
+		Body:       io.NopCloser(strings.NewReader(body)),
 		Status:     status,
 		StatusCode: statusCode,
 	}
diff --git a/gold-client/go/goldclient/goldclient.go b/gold-client/go/goldclient/goldclient.go
index 9676e0a..cc8a63b 100644
--- a/gold-client/go/goldclient/goldclient.go
+++ b/gold-client/go/goldclient/goldclient.go
@@ -10,7 +10,6 @@
 	"fmt"
 	"image"
 	"image/png"
-	"io/ioutil"
 	"math"
 	"net/url"
 	"os"
@@ -226,7 +225,7 @@
 // the bytes of the encoded image and the MD5 hash of the pixels as hex encoded string.
 func loadAndHashImage(fileName string) ([]byte, types.Digest, error) {
 	// Load the image and save the bytes because we need to return them.
-	imgBytes, err := ioutil.ReadFile(fileName)
+	imgBytes, err := os.ReadFile(fileName)
 	if err != nil {
 		return nil, "", skerr.Wrapf(err, "loading file %s", fileName)
 	}
@@ -665,7 +664,7 @@
 	}
 
 	origFilePath := filepath.Join(outDir, fmt.Sprintf("input-%s.png", inputDigest))
-	if err := ioutil.WriteFile(origFilePath, b, 0644); err != nil {
+	if err := os.WriteFile(origFilePath, b, 0644); err != nil {
 		return skerr.Wrapf(err, "writing to %s", origFilePath)
 	}
 
@@ -724,7 +723,7 @@
 
 	// 4) Write closest image and the diff to that image to the output directory.
 	o := filepath.Join(outDir, fmt.Sprintf("closest-%s.png", closestRightDigest))
-	if err := ioutil.WriteFile(o, closestRightImg, 0644); err != nil {
+	if err := os.WriteFile(o, closestRightImg, 0644); err != nil {
 		return skerr.Wrapf(err, "writing closest image to %s", o)
 	}
 
@@ -765,7 +764,7 @@
 	digestPath := filepath.Join(cachePath, string(digest)+".png")
 
 	// Try to read digest from the local cache.
-	digestBytes, err := ioutil.ReadFile(digestPath)
+	digestBytes, err := os.ReadFile(digestPath)
 	if err != nil && !os.IsNotExist(err) {
 		return nil, nil, skerr.Wrapf(err, "reading file %s", digestPath)
 	}
@@ -782,7 +781,7 @@
 		}
 
 		// Cache digest.
-		if err := ioutil.WriteFile(digestPath, digestBytes, 0644); err != nil {
+		if err := os.WriteFile(digestPath, digestBytes, 0644); err != nil {
 			return nil, nil, skerr.Wrapf(err, "caching to %s", digestPath)
 		}
 	}
diff --git a/gold-client/go/goldclient/goldclient_test.go b/gold-client/go/goldclient/goldclient_test.go
index 0721ae0..6b18370 100644
--- a/gold-client/go/goldclient/goldclient_test.go
+++ b/gold-client/go/goldclient/goldclient_test.go
@@ -9,7 +9,6 @@
 	"image"
 	"image/png"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"path/filepath"
@@ -747,7 +746,7 @@
 	// (and the digest is brand new)
 	assert.False(t, pass)
 
-	b, err := ioutil.ReadFile(filepath.Join(wd, failureLog))
+	b, err := os.ReadFile(filepath.Join(wd, failureLog))
 	assert.NoError(t, err)
 	assert.Equal(t, "https://testing-gold.skia.org/detail?grouping=name%3DTestNotSeenBefore%26source_type%3Dtesting&digest=9d0568469d206c1aedf1b71f12f474bc&changelist_id=867&crs=gerrit\n", string(b))
 }
@@ -965,7 +964,7 @@
 
 	// Mock out RPC to automatically triage the new image as positive.
 	bodyMatcher := mock.MatchedBy(func(r io.Reader) bool {
-		b, err := ioutil.ReadAll(r)
+		b, err := io.ReadAll(r)
 		assert.NoError(t, err)
 		if len(b) == 0 {
 			// This matcher can get called a second time during AssertExpectations. This check makes sure
@@ -1097,7 +1096,7 @@
 	// Returns false because the test is negative
 	assert.False(t, pass)
 
-	b, err := ioutil.ReadFile(filepath.Join(wd, failureLog))
+	b, err := os.ReadFile(filepath.Join(wd, failureLog))
 	assert.NoError(t, err)
 	assert.Equal(t, `https://testing-gold.skia.org/detail?grouping=name%3DThisIsTheOnlyTest%26source_type%3Dtesting&digest=badbadbad1325855590527db196112e0&changelist_id=867&crs=gerrit
 https://testing-gold.skia.org/detail?grouping=name%3DThisIsTheOnlyTest%26source_type%3Dtesting&digest=badbadbad1325855590527db196112e0&changelist_id=867&crs=gerrit
@@ -1185,7 +1184,7 @@
 	assert.NoError(t, err)
 	assert.True(t, pass)
 
-	baselineBytes, err := ioutil.ReadFile(goldClient.getResultStatePath())
+	baselineBytes, err := os.ReadFile(goldClient.getResultStatePath())
 	assert.NoError(t, err)
 	// spot check that the expectations were written to disk
 	assert.Contains(t, string(baselineBytes), imgHash)
@@ -1238,7 +1237,7 @@
 	assert.NoError(t, err)
 	assert.True(t, pass)
 
-	baselineBytes, err := ioutil.ReadFile(goldClient.getResultStatePath())
+	baselineBytes, err := os.ReadFile(goldClient.getResultStatePath())
 	assert.NoError(t, err)
 	// spot check that the expectations were written to disk
 	assert.Contains(t, string(baselineBytes), imgHash)
@@ -2277,7 +2276,7 @@
 	assert.NoError(t, err)
 
 	// Write cached digest to disk.
-	err = ioutil.WriteFile(filepath.Join(wd, digestsDirectory, string(digest)+".png"), digestBytes, os.ModePerm)
+	err = os.WriteFile(filepath.Join(wd, digestsDirectory, string(digest)+".png"), digestBytes, os.ModePerm)
 	assert.NoError(t, err)
 
 	actualImage, actualBytes, err := goldClient.getDigestFromCacheOrGCS(ctx, digest)
@@ -2305,7 +2304,7 @@
 	assert.NoError(t, err)
 
 	// Write cached digest to disk.
-	err = ioutil.WriteFile(filepath.Join(wd, digestsDirectory, string(digest)+".png"), digestBytes, os.ModePerm)
+	err = os.WriteFile(filepath.Join(wd, digestsDirectory, string(digest)+".png"), digestBytes, os.ModePerm)
 	assert.NoError(t, err)
 
 	_, _, err = goldClient.getDigestFromCacheOrGCS(ctx, digest)
@@ -2382,7 +2381,7 @@
 	url := "https://testing-gold.skia.org/json/v2/triage"
 	contentType := "application/json"
 	bodyMatcher := mock.MatchedBy(func(r io.Reader) bool {
-		b, err := ioutil.ReadAll(r)
+		b, err := io.ReadAll(r)
 		assert.NoError(t, err)
 		if len(b) == 0 {
 			// This matcher can get called a second time during AssertExpectations. This check makes sure
@@ -2432,7 +2431,7 @@
 	url := "https://testing-gold.skia.org/json/v2/triage"
 	contentType := "application/json"
 	bodyMatcher := mock.MatchedBy(func(r io.Reader) bool {
-		b, err := ioutil.ReadAll(r)
+		b, err := io.ReadAll(r)
 		assert.NoError(t, err)
 		if len(b) == 0 {
 			// This matcher can get called a second time during AssertExpectations. This check makes sure
diff --git a/gold-client/go/imagedownloader/imagedownloader.go b/gold-client/go/imagedownloader/imagedownloader.go
index 3594d80..bb7d975 100644
--- a/gold-client/go/imagedownloader/imagedownloader.go
+++ b/gold-client/go/imagedownloader/imagedownloader.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"io"
 
 	"go.skia.org/infra/go/skerr"
 	"go.skia.org/infra/go/util"
@@ -35,7 +35,7 @@
 		return nil, skerr.Wrapf(err, "getting digest from url %s", u)
 	}
 	defer util.Close(resp.Body)
-	return ioutil.ReadAll(resp.Body)
+	return io.ReadAll(resp.Body)
 }
 
 type DryRunImpl struct{}
diff --git a/gold-client/go/imgmatching/sobel/sobel_test.go b/gold-client/go/imgmatching/sobel/sobel_test.go
index def7677..f4e7c75 100644
--- a/gold-client/go/imgmatching/sobel/sobel_test.go
+++ b/gold-client/go/imgmatching/sobel/sobel_test.go
@@ -6,7 +6,7 @@
 	"image"
 	"image/draw"
 	"image/png"
-	"io/ioutil"
+	"os"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
@@ -759,7 +759,7 @@
 // readPng reads a PNG image from the file system and returns it as an *image.NRGBA.
 func readPng(t *testing.T, filename string) *image.NRGBA {
 	// Read image.
-	imgBytes, err := ioutil.ReadFile(filename)
+	imgBytes, err := os.ReadFile(filename)
 	require.NoError(t, err)
 
 	// Decode image.
diff --git a/golden/cmd/diffcalculator/diffcalculator.go b/golden/cmd/diffcalculator/diffcalculator.go
index 4375416..ed8cda3 100644
--- a/golden/cmd/diffcalculator/diffcalculator.go
+++ b/golden/cmd/diffcalculator/diffcalculator.go
@@ -5,7 +5,7 @@
 import (
 	"context"
 	"flag"
-	"io/ioutil"
+	"io"
 	"math/rand"
 	"net/http"
 	"path"
@@ -236,7 +236,7 @@
 		return nil, skerr.Wrap(err)
 	}
 	defer util.Close(r)
-	b, err := ioutil.ReadAll(r)
+	b, err := io.ReadAll(r)
 	return b, skerr.Wrap(err)
 }
 
diff --git a/golden/cmd/gold_frontend/gold_frontend.go b/golden/cmd/gold_frontend/gold_frontend.go
index 2a6b992..8146822 100644
--- a/golden/cmd/gold_frontend/gold_frontend.go
+++ b/golden/cmd/gold_frontend/gold_frontend.go
@@ -7,7 +7,6 @@
 	"flag"
 	"fmt"
 	"html/template"
-	"io/ioutil"
 	"math/rand"
 	"net/http"
 	"net/http/pprof"
@@ -337,7 +336,7 @@
 				sklog.Fatal("You must specify github_repo and github_cred_path")
 				return nil
 			}
-			gBody, err := ioutil.ReadFile(cfg.GitHubCredPath)
+			gBody, err := os.ReadFile(cfg.GitHubCredPath)
 			if err != nil {
 				sklog.Fatalf("Couldn't find githubToken in %s: %s", cfg.GitHubCredPath, err)
 				return nil
diff --git a/golden/cmd/goldpushk/goldpushk/goldpushk.go b/golden/cmd/goldpushk/goldpushk/goldpushk.go
index 410b99d..b0805bd 100644
--- a/golden/cmd/goldpushk/goldpushk/goldpushk.go
+++ b/golden/cmd/goldpushk/goldpushk/goldpushk.go
@@ -283,11 +283,11 @@
 		// as one will overwrite the other. If it becomes a problem, we could try to detect it.
 		dstFile := filepath.Join(checkoutDir, "gold-"+jf.Name())
 		srcFile := filepath.Join(configDir, jf.Name())
-		b, err := ioutil.ReadFile(srcFile)
+		b, err := os.ReadFile(srcFile)
 		if err != nil {
 			return skerr.Wrapf(err, "reading %s", srcFile)
 		}
-		if err := ioutil.WriteFile(dstFile, b, 0644); err != nil {
+		if err := os.WriteFile(dstFile, b, 0644); err != nil {
 			return skerr.Wrapf(err, "writing %s", dstFile)
 		}
 	}
diff --git a/golden/cmd/goldpushk/goldpushk/goldpushk_test.go b/golden/cmd/goldpushk/goldpushk/goldpushk_test.go
index d672d9a..fca5bbd 100644
--- a/golden/cmd/goldpushk/goldpushk/goldpushk_test.go
+++ b/golden/cmd/goldpushk/goldpushk/goldpushk_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"io"
 	"os"
 	"path/filepath"
 	"testing"
@@ -81,7 +81,7 @@
 	require.NotEqual(t, g.k8sConfigCheckout.GitDir, fakeK8sConfig.Dir())
 
 	// Read README.md from the checkout.
-	k8sConfigReadmeMdBytes, err := ioutil.ReadFile(filepath.Join(string(g.k8sConfigCheckout.GitDir), "README.md"))
+	k8sConfigReadmeMdBytes, err := os.ReadFile(filepath.Join(string(g.k8sConfigCheckout.GitDir), "README.md"))
 	require.NoError(t, err)
 
 	// Assert that file README.md has the expected contents.
@@ -822,7 +822,7 @@
 func writeFileIntoRepo(t *testing.T, repo *git.TempCheckout, name, contents string) {
 	bytes := []byte(contents)
 	path := filepath.Join(string(repo.GitDir), name)
-	err := ioutil.WriteFile(path, bytes, os.ModePerm)
+	err := os.WriteFile(path, bytes, os.ModePerm)
 	require.NoError(t, err)
 }
 
@@ -836,7 +836,7 @@
 	}
 
 	// Replace os.Stdout with a temporary file.
-	fakeStdout, err := ioutil.TempFile("", "fake-stdout")
+	fakeStdout, err := os.CreateTemp("", "fake-stdout")
 	require.NoError(t, err)
 	os.Stdout = fakeStdout
 
@@ -848,7 +848,7 @@
 	// Read the captured stdout.
 	_, err := fakeStdout.Seek(0, 0)
 	require.NoError(t, err)
-	stdoutBytes, err := ioutil.ReadAll(fakeStdout)
+	stdoutBytes, err := io.ReadAll(fakeStdout)
 	require.NoError(t, err)
 	return string(stdoutBytes)
 }
@@ -863,7 +863,7 @@
 	}
 
 	// Create new file to be used as a fake stdin.
-	fakeStdin, err := ioutil.TempFile("", "fake-stdin")
+	fakeStdin, err := os.CreateTemp("", "fake-stdin")
 	require.NoError(t, err)
 
 	// Write fake user input.
diff --git a/golden/cmd/periodictasks/periodictasks.go b/golden/cmd/periodictasks/periodictasks.go
index bda4325..3b2ecc9 100644
--- a/golden/cmd/periodictasks/periodictasks.go
+++ b/golden/cmd/periodictasks/periodictasks.go
@@ -6,8 +6,8 @@
 	"encoding/json"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"net/http"
+	"os"
 	"strings"
 	"time"
 
@@ -239,7 +239,7 @@
 			if cfg.GitHubRepo == "" || cfg.GitHubCredPath == "" {
 				sklog.Fatal("You must specify github_repo and github_cred_path")
 			}
-			gBody, err := ioutil.ReadFile(cfg.GitHubCredPath)
+			gBody, err := os.ReadFile(cfg.GitHubCredPath)
 			if err != nil {
 				sklog.Fatalf("Couldn't find githubToken in %s: %s", cfg.GitHubCredPath, err)
 			}
diff --git a/golden/cmd/pubsubtool/pubsubtool.go b/golden/cmd/pubsubtool/pubsubtool.go
index 8ba8391..92bcb38 100644
--- a/golden/cmd/pubsubtool/pubsubtool.go
+++ b/golden/cmd/pubsubtool/pubsubtool.go
@@ -6,7 +6,6 @@
 	"context"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"strings"
 	"time"
@@ -80,7 +79,7 @@
 	if topic == "" || jsonMessageFile == "" {
 		return skerr.Fmt("Can't have empty topic or message file")
 	}
-	body, err := ioutil.ReadFile(jsonMessageFile)
+	body, err := os.ReadFile(jsonMessageFile)
 	if err != nil {
 		return skerr.Wrapf(err, "reading %s", jsonMessageFile)
 	}
diff --git a/golden/go/diff/worker/worker2_test.go b/golden/go/diff/worker/worker2_test.go
index ee45591..d03361b 100644
--- a/golden/go/diff/worker/worker2_test.go
+++ b/golden/go/diff/worker/worker2_test.go
@@ -4,7 +4,7 @@
 	"bytes"
 	"context"
 	"errors"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"testing"
 	"time"
@@ -210,9 +210,9 @@
 	db := sqltest.NewCockroachDBForTestsWithProductionSchema(ctx, t)
 	waitForSystemTime()
 	// Set up an image source that can download A01 and A02, but returns error on A04
-	b01, err := ioutil.ReadFile(filepath.Join(kitchenSinkRoot(t), string(dks.DigestA01Pos)+".png"))
+	b01, err := os.ReadFile(filepath.Join(kitchenSinkRoot(t), string(dks.DigestA01Pos)+".png"))
 	require.NoError(t, err)
-	b02, err := ioutil.ReadFile(filepath.Join(kitchenSinkRoot(t), string(dks.DigestA02Pos)+".png"))
+	b02, err := os.ReadFile(filepath.Join(kitchenSinkRoot(t), string(dks.DigestA02Pos)+".png"))
 	require.NoError(t, err)
 	mis := &mocks.ImageSource{}
 	mis.On("GetImage", testutils.AnyContext, dks.DigestA01Pos).Return(b01, nil)
@@ -261,9 +261,9 @@
 	waitForSystemTime()
 
 	// Set up an image source that can download A01 and A02, but invalid PNG data for A04
-	b01, err := ioutil.ReadFile(filepath.Join(kitchenSinkRoot(t), string(dks.DigestA01Pos)+".png"))
+	b01, err := os.ReadFile(filepath.Join(kitchenSinkRoot(t), string(dks.DigestA01Pos)+".png"))
 	require.NoError(t, err)
-	b02, err := ioutil.ReadFile(filepath.Join(kitchenSinkRoot(t), string(dks.DigestA02Pos)+".png"))
+	b02, err := os.ReadFile(filepath.Join(kitchenSinkRoot(t), string(dks.DigestA02Pos)+".png"))
 	require.NoError(t, err)
 	mis := &mocks.ImageSource{}
 	mis.On("GetImage", testutils.AnyContext, dks.DigestA01Pos).Return(b01, nil)
@@ -439,7 +439,7 @@
 
 func (f fsImageSource) GetImage(_ context.Context, digest types.Digest) ([]byte, error) {
 	p := filepath.Join(f.root, string(digest)+".png")
-	return ioutil.ReadFile(p)
+	return os.ReadFile(p)
 }
 
 func kitchenSinkRoot(t *testing.T) string {
diff --git a/golden/go/ingestion_processors/primarysql_test.go b/golden/go/ingestion_processors/primarysql_test.go
index 53af727..9cad650 100644
--- a/golden/go/ingestion_processors/primarysql_test.go
+++ b/golden/go/ingestion_processors/primarysql_test.go
@@ -6,7 +6,7 @@
 	"crypto/md5"
 	"encoding/hex"
 	"io"
-	"io/ioutil"
+	"os"
 	"path/filepath"
 	"sync"
 	"testing"
@@ -1539,13 +1539,13 @@
 
 func fakeGCSSourceFromFile(t *testing.T, file string) *fakeGCSSource {
 	fp := filepath.Join(testutils.TestDataDir(t), file)
-	b, err := ioutil.ReadFile(fp)
+	b, err := os.ReadFile(fp)
 	require.NoError(t, err)
 	return &fakeGCSSource{content: b}
 }
 
 func (f *fakeGCSSource) GetReader(_ context.Context, _ string) (io.ReadCloser, error) {
-	return ioutil.NopCloser(bytes.NewReader(f.content)), nil
+	return io.NopCloser(bytes.NewReader(f.content)), nil
 }
 
 func (f *fakeGCSSource) HandlesFile(_ string) bool {
diff --git a/golden/go/ingestion_processors/tryjob_ingestion.go b/golden/go/ingestion_processors/tryjob_ingestion.go
index b963878..c833cd2 100644
--- a/golden/go/ingestion_processors/tryjob_ingestion.go
+++ b/golden/go/ingestion_processors/tryjob_ingestion.go
@@ -4,8 +4,8 @@
 	"context"
 	"crypto/md5"
 	"fmt"
-	"io/ioutil"
 	"net/http"
+	"os"
 	"strings"
 	"time"
 
@@ -188,7 +188,7 @@
 		if strings.TrimSpace(githubCredPath) == "" {
 			return nil, skerr.Fmt("missing credentials path for the GitHub code review system")
 		}
-		gBody, err := ioutil.ReadFile(githubCredPath)
+		gBody, err := os.ReadFile(githubCredPath)
 		if err != nil {
 			return nil, skerr.Wrapf(err, "reading githubToken in %s", githubCredPath)
 		}
diff --git a/golden/go/sql/exporter/tosql/tosql.go b/golden/go/sql/exporter/tosql/tosql.go
index 3c9cd9c..7c7ef9c 100644
--- a/golden/go/sql/exporter/tosql/tosql.go
+++ b/golden/go/sql/exporter/tosql/tosql.go
@@ -5,7 +5,6 @@
 
 import (
 	"flag"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -25,7 +24,7 @@
 
 	generatedText := exporter.GenerateSQL(schema.Tables{}, *outputPkg, exporter.SchemaOnly)
 	out := filepath.Join(cwd, *outputFile)
-	err = ioutil.WriteFile(out, []byte(generatedText), 0666)
+	err = os.WriteFile(out, []byte(generatedText), 0666)
 	if err != nil {
 		sklog.Fatalf("Could not write SQL to %s: %s", out, err)
 	}
diff --git a/golden/go/storage/gcsclient.go b/golden/go/storage/gcsclient.go
index d155623..1de8b49 100644
--- a/golden/go/storage/gcsclient.go
+++ b/golden/go/storage/gcsclient.go
@@ -4,7 +4,6 @@
 	"context"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"path"
 
@@ -171,7 +170,7 @@
 		return nil, skerr.Wrap(err)
 	}
 	defer util.Close(r)
-	b, err := ioutil.ReadAll(r)
+	b, err := io.ReadAll(r)
 	return b, skerr.Wrap(err)
 }
 
diff --git a/infra-sk/sk_demo_page_server/demo_page_server.go b/infra-sk/sk_demo_page_server/demo_page_server.go
index 6798829..4207928 100644
--- a/infra-sk/sk_demo_page_server/demo_page_server.go
+++ b/infra-sk/sk_demo_page_server/demo_page_server.go
@@ -5,7 +5,6 @@
 import (
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"net"
 	"net/http"
 	"os"
@@ -97,13 +96,13 @@
 	if testOnEnv {
 		// First, we write out the TCP port number. This will be read by the test target.
 		envPortFile := path.Join(envDir, envPortFileBaseName)
-		err = ioutil.WriteFile(envPortFile, []byte(strconv.Itoa(actualPort)), 0644)
+		err = os.WriteFile(envPortFile, []byte(strconv.Itoa(actualPort)), 0644)
 		if err != nil {
 			panic(err)
 		}
 
 		// Then, we write the ready file. This signals the test_on_env runner script that we are ready.
-		err = ioutil.WriteFile(envReadyFile, []byte{}, 0644)
+		err = os.WriteFile(envReadyFile, []byte{}, 0644)
 		if err != nil {
 			panic(err)
 		}
diff --git a/jsfiddle/go/jsfiddle/main.go b/jsfiddle/go/jsfiddle/main.go
index 3670d40..80a7b7e 100644
--- a/jsfiddle/go/jsfiddle/main.go
+++ b/jsfiddle/go/jsfiddle/main.go
@@ -8,9 +8,9 @@
 	"encoding/json"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"mime"
 	"net/http"
+	"os"
 	"path/filepath"
 	"strings"
 
@@ -124,13 +124,13 @@
 }
 
 func loadPages() {
-	if p, err := ioutil.ReadFile(filepath.Join(*resourcesDir, "pathkit-index.html")); err != nil {
+	if p, err := os.ReadFile(filepath.Join(*resourcesDir, "pathkit-index.html")); err != nil {
 		sklog.Fatalf("Could not find pathkit html: %s", err)
 	} else {
 		pathkitPage = p
 	}
 
-	if p, err := ioutil.ReadFile(filepath.Join(*resourcesDir, "canvaskit-index.html")); err != nil {
+	if p, err := os.ReadFile(filepath.Join(*resourcesDir, "canvaskit-index.html")); err != nil {
 		sklog.Fatalf("Could not find canvaskit html: %s", err)
 	} else {
 		canvaskitPage = p
diff --git a/k8s-deployer/go/k8s-deployer/main.go b/k8s-deployer/go/k8s-deployer/main.go
index b24b7c1..73ac980 100644
--- a/k8s-deployer/go/k8s-deployer/main.go
+++ b/k8s-deployer/go/k8s-deployer/main.go
@@ -3,7 +3,6 @@
 import (
 	"context"
 	"flag"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -183,7 +182,7 @@
 	}
 
 	// Write the config contents to a temporary dir.
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	if err != nil {
 		return skerr.Wrapf(err, "failed to create temp dir")
 	}
@@ -197,7 +196,7 @@
 				return skerr.Wrapf(err, "failed to create %s", dir)
 			}
 		}
-		if err := ioutil.WriteFile(fullPath, fileContents, os.ModePerm); err != nil {
+		if err := os.WriteFile(fullPath, fileContents, os.ModePerm); err != nil {
 			return skerr.Wrapf(err, "failed to create %s", fullPath)
 		}
 	}
diff --git a/kube/cmd/k8s-config-presubmit/main.go b/kube/cmd/k8s-config-presubmit/main.go
index 9df7a7a..a3683d2 100644
--- a/kube/cmd/k8s-config-presubmit/main.go
+++ b/kube/cmd/k8s-config-presubmit/main.go
@@ -18,7 +18,6 @@
 	"fmt"
 	"html/template"
 	"io"
-	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -225,7 +224,7 @@
 }
 
 func ValidateAlertFile(ctx context.Context, path string) error {
-	contents, err := ioutil.ReadFile(path)
+	contents, err := os.ReadFile(path)
 	if err != nil {
 		return err
 	}
@@ -268,7 +267,7 @@
 
 func checkK8sConfigFile(ctx context.Context, f fileWithChanges) bool {
 	// Read the configs from the file.
-	contents, err := ioutil.ReadFile(f.fileName)
+	contents, err := os.ReadFile(f.fileName)
 	if err != nil {
 		logf(ctx, "%s\n", err)
 		return false
diff --git a/kube/go/kube_conf_gen_lib/kube_conf_gen_lib.go b/kube/go/kube_conf_gen_lib/kube_conf_gen_lib.go
index 587bbb5..2f4cbdf 100644
--- a/kube/go/kube_conf_gen_lib/kube_conf_gen_lib.go
+++ b/kube/go/kube_conf_gen_lib/kube_conf_gen_lib.go
@@ -3,7 +3,6 @@
 import (
 	"bytes"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -136,6 +135,6 @@
 				return skerr.Wrapf(err, "failed to create destination directory")
 			}
 		}
-		return skerr.Wrap(ioutil.WriteFile(outFile, buf.Bytes(), 0644))
+		return skerr.Wrap(os.WriteFile(outFile, buf.Bytes(), 0644))
 	}
 }
diff --git a/kube/go/pushk/main.go b/kube/go/pushk/main.go
index 143f6a5..6abc3c5 100644
--- a/kube/go/pushk/main.go
+++ b/kube/go/pushk/main.go
@@ -8,7 +8,6 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"regexp"
@@ -295,7 +294,7 @@
 
 		// Loop over all the yaml files and update tags for the given imageName.
 		for _, filename := range filenames {
-			b, err := ioutil.ReadFile(filename)
+			b, err := os.ReadFile(filename)
 			if err != nil {
 				sklog.Errorf("Failed to read %q (skipping): %s", filename, err)
 				continue
diff --git a/kube/go/secrets/main.go b/kube/go/secrets/main.go
index 1e89327..9cd4809 100644
--- a/kube/go/secrets/main.go
+++ b/kube/go/secrets/main.go
@@ -7,7 +7,6 @@
 	"encoding/json"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"runtime"
@@ -177,7 +176,7 @@
 	}
 	defer cleanup()
 	secretFile := filepath.Join(ramdisk, secretName)
-	if err := ioutil.WriteFile(secretFile, []byte(currentValue), os.ModePerm); err != nil {
+	if err := os.WriteFile(secretFile, []byte(currentValue), os.ModePerm); err != nil {
 		return skerr.Wrap(err)
 	}
 	_, _ = fmt.Fprintf(a.stdout, "Wrote secret to %s\n", secretFile)
@@ -186,7 +185,7 @@
 	if _, err := reader.ReadString('\n'); err != nil {
 		return skerr.Wrap(err)
 	}
-	newValue, err := ioutil.ReadFile(secretFile)
+	newValue, err := os.ReadFile(secretFile)
 	if err != nil {
 		return skerr.Wrap(err)
 	}
diff --git a/kube/go/secrets/main_test.go b/kube/go/secrets/main_test.go
index 362ca2e..6bd54f9 100644
--- a/kube/go/secrets/main_test.go
+++ b/kube/go/secrets/main_test.go
@@ -5,7 +5,6 @@
 	"encoding/base64"
 	"encoding/json"
 	"io"
-	"io/ioutil"
 	"os"
 	"regexp"
 	"sync"
@@ -89,10 +88,10 @@
 		require.NoError(t, app.cmdCreate(ctx, testProject, testSecretName))
 	}()
 	secretFilePath := <-secretFileCh
-	secretFileContents, err := ioutil.ReadFile(secretFilePath)
+	secretFileContents, err := os.ReadFile(secretFilePath)
 	require.NoError(t, err)
 	require.Equal(t, "", string(secretFileContents))
-	require.NoError(t, ioutil.WriteFile(secretFilePath, []byte(testSecretValue), os.ModePerm))
+	require.NoError(t, os.WriteFile(secretFilePath, []byte(testSecretValue), os.ModePerm))
 	enterToContinueCh <- true
 	wg.Wait()
 }
@@ -108,10 +107,10 @@
 		require.NoError(t, app.cmdUpdate(ctx, testProject, testSecretName))
 	}()
 	secretFilePath := <-secretFileCh
-	secretFileContents, err := ioutil.ReadFile(secretFilePath)
+	secretFileContents, err := os.ReadFile(secretFilePath)
 	require.NoError(t, err)
 	require.Equal(t, testSecretValue, string(secretFileContents))
-	require.NoError(t, ioutil.WriteFile(secretFilePath, []byte(newSecretValue), os.ModePerm))
+	require.NoError(t, os.WriteFile(secretFilePath, []byte(newSecretValue), os.ModePerm))
 	enterToContinueCh <- true
 	wg.Wait()
 }
diff --git a/machine/go/machine/store/cdb/tosql/main.go b/machine/go/machine/store/cdb/tosql/main.go
index 0005af0..b91ccfc 100644
--- a/machine/go/machine/store/cdb/tosql/main.go
+++ b/machine/go/machine/store/cdb/tosql/main.go
@@ -5,7 +5,6 @@
 package main
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -22,7 +21,7 @@
 
 	generatedText := exporter.GenerateSQL(cdb.Tables{}, "cdb", exporter.SchemaAndColumnNames)
 	out := filepath.Join(cwd, "sql.go")
-	err = ioutil.WriteFile(out, []byte(generatedText), 0666)
+	err = os.WriteFile(out, []byte(generatedText), 0666)
 	if err != nil {
 		sklog.Fatalf("Could not write SQL to %s: %s", out, err)
 	}
diff --git a/machine/go/test_machine_monitor/machine/machine_test.go b/machine/go/test_machine_monitor/machine/machine_test.go
index a12a7eb..3292e1d 100644
--- a/machine/go/test_machine_monitor/machine/machine_test.go
+++ b/machine/go/test_machine_monitor/machine/machine_test.go
@@ -4,7 +4,6 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
 	"net/url"
@@ -1000,7 +999,7 @@
 func writeQuarantineFile(m *Machine, t *testing.T) string {
 	// Write quarantine file.
 	quarantineFile := filepath.Join(m.homeDir, fmt.Sprintf("%s.force_quarantine", machineID))
-	err := ioutil.WriteFile(quarantineFile, []byte("test"), 0666)
+	err := os.WriteFile(quarantineFile, []byte("test"), 0666)
 	require.NoError(t, err)
 
 	// Test the test, confirm the file exists.
diff --git a/machine/go/test_machine_monitor/server/server_test.go b/machine/go/test_machine_monitor/server/server_test.go
index 2cedafa..84c3cde 100644
--- a/machine/go/test_machine_monitor/server/server_test.go
+++ b/machine/go/test_machine_monitor/server/server_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"encoding/json"
-	"io/ioutil"
+	"io"
 	"net/http/httptest"
 	"os"
 	"strings"
@@ -25,7 +25,7 @@
 
 	res := w.Result()
 	assert.Equal(t, 200, res.StatusCode)
-	b, err := ioutil.ReadAll(res.Body)
+	b, err := io.ReadAll(res.Body)
 	require.NoError(t, err)
 	assert.Equal(t, `{"caches":{"isolated":{"size":8589934592}}}`, strings.TrimSpace(string(b)))
 }
diff --git a/machine/go/test_machine_monitor/swarming/swarming.go b/machine/go/test_machine_monitor/swarming/swarming.go
index 90d2c31..a0410b9 100644
--- a/machine/go/test_machine_monitor/swarming/swarming.go
+++ b/machine/go/test_machine_monitor/swarming/swarming.go
@@ -7,7 +7,6 @@
 	"encoding/json"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"os"
 	"os/exec"
@@ -105,7 +104,7 @@
 	if resp.StatusCode != 200 {
 		return skerr.Fmt("Metadata bad status code: %d - %s", resp.StatusCode, resp.Status)
 	}
-	tokenBytes, err := ioutil.ReadAll(resp.Body)
+	tokenBytes, err := io.ReadAll(resp.Body)
 	if err != nil {
 		return skerr.Wrapf(err, "reading body of %s", b.metadataURL)
 	}
diff --git a/machine/go/test_machine_monitor/swarming/swarming_test.go b/machine/go/test_machine_monitor/swarming/swarming_test.go
index 5219ff2..7e37c15 100644
--- a/machine/go/test_machine_monitor/swarming/swarming_test.go
+++ b/machine/go/test_machine_monitor/swarming/swarming_test.go
@@ -4,7 +4,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/http/httptest"
 	"os"
@@ -93,7 +93,7 @@
 // server.
 func newBotForTest(t *testing.T, metadataHander, botCodeHandler http.HandlerFunc) (*Bot, string, cleanupFunc) {
 	// Get a temp dir.
-	dir, err := ioutil.TempDir("", "swarming")
+	dir, err := os.MkdirTemp("", "swarming")
 	require.NoError(t, err)
 
 	// Create a temp file to stand in for the python executable.
@@ -171,7 +171,7 @@
 	require.NoError(t, bot.bootstrap(context.Background()))
 
 	// Confirm that we downloaded the swarming bot contents correctly.
-	b, err := ioutil.ReadFile(swarmingBotPath)
+	b, err := os.ReadFile(swarmingBotPath)
 	require.NoError(t, err)
 	assert.Equal(t, swarmingBotFakeContents, string(b))
 }
@@ -246,7 +246,7 @@
 	// this programs stderr output.
 
 	// First create a temp file.
-	f, err := ioutil.TempFile("", "swarming")
+	f, err := os.CreateTemp("", "swarming")
 	require.NoError(t, err)
 
 	// Now swap out os.Stderr with our file.
@@ -275,7 +275,7 @@
 	// Check the output of sklog.
 	_, err = f.Seek(0, 0)
 	require.NoError(t, err)
-	b, err := ioutil.ReadAll(f)
+	b, err := io.ReadAll(f)
 	require.NoError(t, err)
 	assert.Contains(t, string(b), swarmingbotFakeStderrOutput) // See TestFakeSwarmingExecutable_ExitCodeZero
 }
diff --git a/named-fiddles/go/named-fiddles/main.go b/named-fiddles/go/named-fiddles/main.go
index 5473773..bacad17 100644
--- a/named-fiddles/go/named-fiddles/main.go
+++ b/named-fiddles/go/named-fiddles/main.go
@@ -5,7 +5,6 @@
 	"encoding/json"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"strings"
@@ -134,7 +133,7 @@
 		}
 		name = name[0 : len(name)-4]
 		filename := filepath.Join(dir, info.Name())
-		b, err := ioutil.ReadFile(filename)
+		b, err := os.ReadFile(filename)
 		if err != nil {
 			sklog.Warningf("Failed to load file: %q", filename)
 		}
diff --git a/new_element/main.go b/new_element/main.go
index 02501f7..e285420 100644
--- a/new_element/main.go
+++ b/new_element/main.go
@@ -8,7 +8,6 @@
 import (
 	"flag"
 	"io"
-	"io/ioutil"
 	"log"
 	"net/http"
 	"os"
@@ -117,7 +116,7 @@
 		if err != nil {
 			log.Fatal(err)
 		}
-		b, err := ioutil.ReadAll(file)
+		b, err := io.ReadAll(file)
 		if err != nil {
 			log.Fatal(err)
 		}
diff --git a/perf/demo/generate_data.go b/perf/demo/generate_data.go
index 15fcf86..e6525fe 100644
--- a/perf/demo/generate_data.go
+++ b/perf/demo/generate_data.go
@@ -5,7 +5,6 @@
 import (
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"math/rand"
 	"os"
 	"path"
@@ -91,7 +90,7 @@
 		if err != nil {
 			sklog.Fatal(err)
 		}
-		if err := ioutil.WriteFile(fmt.Sprintf("./data/demo_data_commit_%d.json", i+1), b, 0644); err != nil {
+		if err := os.WriteFile(fmt.Sprintf("./data/demo_data_commit_%d.json", i+1), b, 0644); err != nil {
 			sklog.Fatal(err)
 		}
 	}
diff --git a/perf/go/anomalies/chrome/chrome.go b/perf/go/anomalies/chrome/chrome.go
index 120cd7a..88e1a3d 100644
--- a/perf/go/anomalies/chrome/chrome.go
+++ b/perf/go/anomalies/chrome/chrome.go
@@ -4,7 +4,7 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"strconv"
 	"strings"
@@ -117,7 +117,7 @@
 		return nil, skerr.Wrapf(err, "Failed to get chrome perf response.")
 	}
 
-	respBody, err := ioutil.ReadAll(httpResponse.Body)
+	respBody, err := io.ReadAll(httpResponse.Body)
 	if err != nil {
 		return nil, skerr.Wrapf(err, "Failed to read body from chrome perf response.")
 	}
diff --git a/perf/go/builders/builders_test.go b/perf/go/builders/builders_test.go
index b76e827..82f5f28 100644
--- a/perf/go/builders/builders_test.go
+++ b/perf/go/builders/builders_test.go
@@ -2,7 +2,6 @@
 
 import (
 	"context"
-	"io/ioutil"
 	"os"
 	"testing"
 	"time"
@@ -24,7 +23,7 @@
 
 func TestNewSourceFromConfig_DirSource_Success(t *testing.T) {
 	ctx := context.Background()
-	dir, err := ioutil.TempDir("", "perf-builders")
+	dir, err := os.MkdirTemp("", "perf-builders")
 	require.NoError(t, err)
 	defer func() {
 		assert.NoError(t, os.RemoveAll(dir))
@@ -45,7 +44,7 @@
 
 func TestNewSourceFromConfig_MissingSourceForDirSourceIsError(t *testing.T) {
 	ctx := context.Background()
-	dir, err := ioutil.TempDir("", "perf-builders")
+	dir, err := os.MkdirTemp("", "perf-builders")
 	require.NoError(t, err)
 	defer func() {
 		assert.NoError(t, os.RemoveAll(dir))
diff --git a/perf/go/config/validate/validate.go b/perf/go/config/validate/validate.go
index 74ebcd5..669a9bf 100644
--- a/perf/go/config/validate/validate.go
+++ b/perf/go/config/validate/validate.go
@@ -4,7 +4,6 @@
 	"context"
 	"encoding/json"
 	"io"
-	"io/ioutil"
 	"regexp"
 	"time"
 
@@ -44,7 +43,7 @@
 
 	// Validate config here.
 	err := util.WithReadFile(filename, func(r io.Reader) error {
-		b, err := ioutil.ReadAll(r)
+		b, err := io.ReadAll(r)
 		if err != nil {
 			return skerr.Wrapf(err, "failed to read bytes")
 		}
diff --git a/perf/go/file/gcssource/gcssource_manual_test.go b/perf/go/file/gcssource/gcssource_manual_test.go
index bb1ea2f..b0fe359 100644
--- a/perf/go/file/gcssource/gcssource_manual_test.go
+++ b/perf/go/file/gcssource/gcssource_manual_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"encoding/json"
-	"io/ioutil"
+	"io"
 	"math/rand"
 	"testing"
 	"time"
@@ -145,7 +145,7 @@
 	// Load the one file sendPubSubMessages should have sent.
 	file := <-ch
 	assert.Equal(t, testFile, file.Name)
-	b, err := ioutil.ReadAll(file.Contents)
+	b, err := io.ReadAll(file.Contents)
 	assert.NoError(t, err)
 	assert.NoError(t, file.Contents.Close())
 	assert.Equal(t, "{\n  \"status\": \"Success\"\n}\n", string(b))
@@ -172,7 +172,7 @@
 	// Load the one file sendPubSubMessages should have sent.
 	file := <-ch
 	assert.Equal(t, testFile, file.Name)
-	b, err := ioutil.ReadAll(file.Contents)
+	b, err := io.ReadAll(file.Contents)
 	assert.NoError(t, err)
 	assert.NoError(t, file.Contents.Close())
 	assert.Equal(t, "{\n  \"status\": \"Success\"\n}\n", string(b))
@@ -224,7 +224,7 @@
 	// Confirm the correct file.File comes out of the channel.
 	file := <-ch
 	assert.Equal(t, testFile, file.Name)
-	b, err = ioutil.ReadAll(file.Contents)
+	b, err = io.ReadAll(file.Contents)
 	assert.NoError(t, err)
 	assert.NoError(t, file.Contents.Close())
 	assert.Equal(t, "{\n  \"status\": \"Success\"\n}\n", string(b))
diff --git a/perf/go/frontend/frontend.go b/perf/go/frontend/frontend.go
index 1f9377a..4e8cbc9 100644
--- a/perf/go/frontend/frontend.go
+++ b/perf/go/frontend/frontend.go
@@ -6,8 +6,8 @@
 	"encoding/json"
 	"fmt"
 	"html/template"
+	"io"
 	"io/fs"
-	"io/ioutil"
 	"math/rand"
 	"net/http"
 	"net/http/pprof"
@@ -164,7 +164,7 @@
 	if err != nil {
 		return "", skerr.Wrapf(err, "Failed to open %q", filename)
 	}
-	b, err := ioutil.ReadAll(f)
+	b, err := io.ReadAll(f)
 	if err != nil {
 		return "", skerr.Wrapf(err, "Failed to read %q", filename)
 	}
diff --git a/perf/go/git/gittest/gittest.go b/perf/go/git/gittest/gittest.go
index 4629121..e6a1cce 100644
--- a/perf/go/git/gittest/gittest.go
+++ b/perf/go/git/gittest/gittest.go
@@ -3,7 +3,6 @@
 
 import (
 	"context"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"testing"
@@ -74,7 +73,7 @@
 	db := sqltest.NewCockroachDBForTests(t, "dbgit")
 
 	// Get tmp dir to use for repo checkout.
-	tmpDir, err := ioutil.TempDir("", "git")
+	tmpDir, err := os.MkdirTemp("", "git_repo")
 	require.NoError(t, err)
 
 	// Create the cleanup function.
diff --git a/perf/go/git/providers/git_checkout/git_checkout_test.go b/perf/go/git/providers/git_checkout/git_checkout_test.go
index 04caace..0a7337e 100644
--- a/perf/go/git/providers/git_checkout/git_checkout_test.go
+++ b/perf/go/git/providers/git_checkout/git_checkout_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"os"
 	"path/filepath"
 	"strings"
@@ -46,7 +46,7 @@
 	hashes = append(hashes, gb.CommitGenAt(ctx, "foo.txt", StartTime.Add(7*time.Minute)))
 
 	// Get tmp dir to use for repo checkout.
-	tmpDir, err := ioutil.TempDir("", "git")
+	tmpDir, err := os.MkdirTemp("", "git")
 	require.NoError(t, err)
 
 	// Create the cleanup function.
@@ -73,7 +73,7 @@
 Change #9
 1584837783`)
 
-	err := parseGitRevLogStream(ioutil.NopCloser(r), func(p provider.Commit) error {
+	err := parseGitRevLogStream(io.NopCloser(r), func(p provider.Commit) error {
 		assert.Equal(t, provider.Commit{
 			CommitNumber: types.BadCommitNumber,
 			GitHash:      "6079a7810530025d9877916895dd14eb8bb454c0",
@@ -92,7 +92,7 @@
 Change #9
 1584837783`)
 
-	err := parseGitRevLogStream(ioutil.NopCloser(r), func(p provider.Commit) error {
+	err := parseGitRevLogStream(io.NopCloser(r), func(p provider.Commit) error {
 		return fmt.Errorf("This is an error.")
 	})
 	assert.Contains(t, err.Error(), "This is an error.")
@@ -110,7 +110,7 @@
 1584837780`)
 	count := 0
 	hashes := []string{"6079a7810530025d9877916895dd14eb8bb454c0", "977e0ef44bec17659faf8c5d4025c5a068354817"}
-	err := parseGitRevLogStream(ioutil.NopCloser(r), func(p provider.Commit) error {
+	err := parseGitRevLogStream(io.NopCloser(r), func(p provider.Commit) error {
 		assert.Equal(t, "Joe Gregorio <joe@bitworking.org>", p.Author)
 		assert.Equal(t, hashes[count], p.GitHash)
 		count++
@@ -122,7 +122,7 @@
 
 func TestParseGitRevLogStream_EmptyFile_Success(t *testing.T) {
 	r := strings.NewReader("")
-	err := parseGitRevLogStream(ioutil.NopCloser(r), func(p provider.Commit) error {
+	err := parseGitRevLogStream(io.NopCloser(r), func(p provider.Commit) error {
 		assert.Fail(t, "Should never get here.")
 		return nil
 	})
@@ -134,7 +134,7 @@
 		`commit 6079a7810530025d9877916895dd14eb8bb454c0
 Joe Gregorio <joe@bitworking.org>
 Change #9`)
-	err := parseGitRevLogStream(ioutil.NopCloser(r), func(p provider.Commit) error {
+	err := parseGitRevLogStream(io.NopCloser(r), func(p provider.Commit) error {
 		assert.Fail(t, "Should never get here.")
 		return nil
 	})
@@ -147,7 +147,7 @@
 Joe Gregorio <joe@bitworking.org>
 Change #9
 ooops 1584837780`)
-	err := parseGitRevLogStream(ioutil.NopCloser(r), func(p provider.Commit) error {
+	err := parseGitRevLogStream(io.NopCloser(r), func(p provider.Commit) error {
 		assert.Fail(t, "Should never get here.")
 		return nil
 	})
@@ -158,7 +158,7 @@
 	r := strings.NewReader(
 		`commit 6079a7810530025d9877916895dd14eb8bb454c0
 Joe Gregorio <joe@bitworking.org>`)
-	err := parseGitRevLogStream(ioutil.NopCloser(r), func(p provider.Commit) error {
+	err := parseGitRevLogStream(io.NopCloser(r), func(p provider.Commit) error {
 		assert.Fail(t, "Should never get here.")
 		return nil
 	})
@@ -168,7 +168,7 @@
 func TestParseGitRevLogStream_ErrMissingAuthor(t *testing.T) {
 	r := strings.NewReader(
 		`commit 6079a7810530025d9877916895dd14eb8bb454c0`)
-	err := parseGitRevLogStream(ioutil.NopCloser(r), func(p provider.Commit) error {
+	err := parseGitRevLogStream(io.NopCloser(r), func(p provider.Commit) error {
 		assert.Fail(t, "Should never get here.")
 		return nil
 	})
@@ -178,7 +178,7 @@
 func TestParseGitRevLogStream_ErrMalformedCommitLine(t *testing.T) {
 	r := strings.NewReader(
 		`something_not_commit 6079a7810530025d9877916895dd14eb8bb454c0`)
-	err := parseGitRevLogStream(ioutil.NopCloser(r), func(p provider.Commit) error {
+	err := parseGitRevLogStream(io.NopCloser(r), func(p provider.Commit) error {
 		assert.Fail(t, "Should never get here.")
 		return nil
 	})
diff --git a/perf/go/ingest/format/format.go b/perf/go/ingest/format/format.go
index bce14d6..d89e89d 100644
--- a/perf/go/ingest/format/format.go
+++ b/perf/go/ingest/format/format.go
@@ -7,7 +7,6 @@
 	"encoding/json"
 	"errors"
 	"io"
-	"io/ioutil"
 
 	"go.skia.org/infra/go/jsonschema"
 	"go.skia.org/infra/go/skerr"
@@ -209,7 +208,7 @@
 // If there was an error loading the file a list of schema violations may be
 // returned also.
 func Validate(ctx context.Context, r io.Reader) ([]string, error) {
-	b, err := ioutil.ReadAll(r)
+	b, err := io.ReadAll(r)
 	if err != nil {
 		return nil, skerr.Wrapf(err, "failed to read bytes")
 	}
diff --git a/perf/go/ingest/parser/parser.go b/perf/go/ingest/parser/parser.go
index 1ace256..e2f1751 100644
--- a/perf/go/ingest/parser/parser.go
+++ b/perf/go/ingest/parser/parser.go
@@ -6,7 +6,6 @@
 	"context"
 	"errors"
 	"io"
-	"io/ioutil"
 	"regexp"
 	"strconv"
 	"strings"
@@ -255,7 +254,7 @@
 	// Read the whole content into bytes.Reader since we may take more than one
 	// pass at the data.
 	sklog.Infof("About to read.")
-	b, err := ioutil.ReadAll(file.Contents)
+	b, err := io.ReadAll(file.Contents)
 	sklog.Infof("Finished readall.")
 	if err != nil {
 		p.parseFailCounter.Inc(1)
@@ -302,7 +301,7 @@
 
 	// Read the whole content into bytes.Reader since we may take more than one
 	// pass at the data.
-	b, err := ioutil.ReadAll(file.Contents)
+	b, err := io.ReadAll(file.Contents)
 	if err != nil {
 		p.parseFailCounter.Inc(1)
 		return "", "", skerr.Wrap(err)
diff --git a/perf/go/ingest/parser/parser_test.go b/perf/go/ingest/parser/parser_test.go
index fc86ba2..6bd6746 100644
--- a/perf/go/ingest/parser/parser_test.go
+++ b/perf/go/ingest/parser/parser_test.go
@@ -4,7 +4,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"path/filepath"
 	"testing"
 
@@ -216,7 +216,7 @@
 }
 
 func parseTryBot_ReadErr(t *testing.T, p *Parser, f file.File) {
-	f.Contents = ioutil.NopCloser(alwaysErrReader{})
+	f.Contents = io.NopCloser(alwaysErrReader{})
 	_, _, err := p.ParseTryBot(f)
 	require.Error(t, err)
 	assert.Equal(t, int64(1), p.parseCounter.Get())
@@ -224,7 +224,7 @@
 }
 
 func parse_ReadErr(t *testing.T, p *Parser, f file.File) {
-	f.Contents = ioutil.NopCloser(alwaysErrReader{})
+	f.Contents = io.NopCloser(alwaysErrReader{})
 	_, _, _, err := p.Parse(context.Background(), f)
 	require.Error(t, err)
 	assert.Equal(t, int64(1), p.parseCounter.Get())
diff --git a/perf/go/ingest/process/process_manual_test.go b/perf/go/ingest/process/process_manual_test.go
index 28e077d..5b4db55 100644
--- a/perf/go/ingest/process/process_manual_test.go
+++ b/perf/go/ingest/process/process_manual_test.go
@@ -4,8 +4,8 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"math/rand"
+	"os"
 	"path/filepath"
 	"sync"
 	"testing"
@@ -65,7 +65,7 @@
 	_ = sqltest.NewCockroachDBForTests(t, CockroachDatabaseName)
 
 	// Get tmp dir to use for repo checkout.
-	tmpDir, err := ioutil.TempDir("", "ingest-process")
+	tmpDir, err := os.MkdirTemp("", "ingest-process")
 	require.NoError(t, err)
 	tmpDir = filepath.Join(tmpDir, "repo")
 
diff --git a/perf/go/notify/notify_test.go b/perf/go/notify/notify_test.go
index 00bd469..fb60aaf 100644
--- a/perf/go/notify/notify_test.go
+++ b/perf/go/notify/notify_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"errors"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/http/httptest"
 	"testing"
@@ -182,7 +182,7 @@
 	subjects := []string{newHTMLSubject, missingHTMLSubject}
 	subjectIndex := 0
 	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		b, err := ioutil.ReadAll(r.Body)
+		b, err := io.ReadAll(r.Body)
 		require.NoError(t, err)
 		require.Contains(t, string(b), "<b>Alert</b>")
 		require.Contains(t, string(b), subjects[subjectIndex])
diff --git a/perf/go/perf-tool/application/application.go b/perf/go/perf-tool/application/application.go
index 684c1f0..eff25d2 100644
--- a/perf/go/perf-tool/application/application.go
+++ b/perf/go/perf-tool/application/application.go
@@ -8,7 +8,6 @@
 	"encoding/json"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/url"
 	"os"
 	"sort"
@@ -798,14 +797,14 @@
 		return nil
 	}
 	return util.WithReadFile(inputFile, func(r io.Reader) error {
-		b, err := ioutil.ReadAll(r)
+		b, err := io.ReadAll(r)
 		if err != nil {
 			return fmt.Errorf("Read Failed: %s", err)
 		}
 		reader := bytes.NewReader(b)
 		f := file.File{
 			Name:     inputFile,
-			Contents: ioutil.NopCloser(reader),
+			Contents: io.NopCloser(reader),
 		}
 		instanceConfig := &config.InstanceConfig{
 			IngestionConfig: config.IngestionConfig{
diff --git a/perf/go/perf-tool/main_test.go b/perf/go/perf-tool/main_test.go
index 860fcca..a5c8735 100644
--- a/perf/go/perf-tool/main_test.go
+++ b/perf/go/perf-tool/main_test.go
@@ -3,7 +3,6 @@
 
 import (
 	"encoding/json"
-	"io/ioutil"
 	"os"
 	"testing"
 
@@ -26,7 +25,7 @@
 			Sections: []config.FavoritesSectionConfig{},
 		},
 	}
-	f, err := ioutil.TempFile("", "perf-tool")
+	f, err := os.CreateTemp("", "perf-tool")
 	require.NoError(t, err)
 	t.Cleanup(func() { require.NoError(t, os.Remove(f.Name())) })
 	err = json.NewEncoder(f).Encode(instanceConfig)
diff --git a/perf/go/pinpoint/pinpoint.go b/perf/go/pinpoint/pinpoint.go
index 6e7bf4d..b903252 100644
--- a/perf/go/pinpoint/pinpoint.go
+++ b/perf/go/pinpoint/pinpoint.go
@@ -5,7 +5,7 @@
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/url"
 
@@ -78,7 +78,7 @@
 	}
 	sklog.Debugf("Got response from Pinpoint service: %+v", *httpResponse)
 
-	respBody, err := ioutil.ReadAll(httpResponse.Body)
+	respBody, err := io.ReadAll(httpResponse.Body)
 	if err != nil {
 		pc.createBisectFailed.Inc(1)
 		return nil, skerr.Wrapf(err, "Failed to read body from pinpoint response.")
diff --git a/perf/go/progress/tracker_test.go b/perf/go/progress/tracker_test.go
index 8915267..87013bb 100644
--- a/perf/go/progress/tracker_test.go
+++ b/perf/go/progress/tracker_test.go
@@ -3,7 +3,7 @@
 import (
 	"bytes"
 	"context"
-	"io/ioutil"
+	"io"
 	"net/http/httptest"
 	"testing"
 	"time"
@@ -95,7 +95,7 @@
 	assert.Equal(t, "application/json", w.Result().Header.Get("Content-Type"))
 	var expectedBody bytes.Buffer
 	require.NoError(t, p.JSON(&expectedBody))
-	actualBody, err := ioutil.ReadAll(w.Result().Body)
+	actualBody, err := io.ReadAll(w.Result().Body)
 	require.NoError(t, err)
 	assert.Equal(t, expectedBody.String(), string(actualBody))
 }
@@ -112,6 +112,6 @@
 	w := httptest.NewRecorder()
 	tr.Handler(w, r)
 	assert.Equal(t, 500, w.Result().StatusCode)
-	actualBody, err := ioutil.ReadAll(w.Result().Body)
+	actualBody, err := io.ReadAll(w.Result().Body)
 	assert.Contains(t, string(actualBody), "Failed to serialize JSON")
 }
diff --git a/perf/go/sql/tosql/main.go b/perf/go/sql/tosql/main.go
index 31d424c..88ebd18 100644
--- a/perf/go/sql/tosql/main.go
+++ b/perf/go/sql/tosql/main.go
@@ -5,7 +5,6 @@
 package main
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -22,7 +21,7 @@
 
 	generatedText := exporter.GenerateSQL(sql.Tables{}, "sql", exporter.SchemaAndColumnNames)
 	out := filepath.Join(cwd, "schema.go")
-	err = ioutil.WriteFile(out, []byte(generatedText), 0666)
+	err = os.WriteFile(out, []byte(generatedText), 0666)
 	if err != nil {
 		sklog.Fatalf("Could not write SQL to %s: %s", out, err)
 	}
diff --git a/perf/go/trybot/samplesloader/gcssamplesloader/gcssamplesloader_test.go b/perf/go/trybot/samplesloader/gcssamplesloader/gcssamplesloader_test.go
index 8afd5d8..c40752f 100644
--- a/perf/go/trybot/samplesloader/gcssamplesloader/gcssamplesloader_test.go
+++ b/perf/go/trybot/samplesloader/gcssamplesloader/gcssamplesloader_test.go
@@ -5,7 +5,7 @@
 	"bytes"
 	"context"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"testing"
 
 	"github.com/stretchr/testify/require"
@@ -67,7 +67,7 @@
 
 	gcsclient := &test_gcsclient.GCSClient{}
 	r := bytes.NewBufferString(sourceFileBody)
-	gcsclient.On("FileReader", testutils.AnyContext, sourceFilePath).Return(ioutil.NopCloser(r), nil)
+	gcsclient.On("FileReader", testutils.AnyContext, sourceFilePath).Return(io.NopCloser(r), nil)
 
 	g := New(gcsclient, ingestParser(t))
 	sampleSet, err := g.Load(ctx, sourceFileName)
@@ -113,7 +113,7 @@
 
 	gcsclient := &test_gcsclient.GCSClient{}
 	r := bytes.NewBufferString("}this isn't valid JSON{")
-	gcsclient.On("FileReader", testutils.AnyContext, sourceFilePath).Return(ioutil.NopCloser(r), nil)
+	gcsclient.On("FileReader", testutils.AnyContext, sourceFilePath).Return(io.NopCloser(r), nil)
 
 	g := New(gcsclient, ingestParser(t))
 	_, err := g.Load(ctx, sourceFileName)
diff --git a/perf/integration/generate_data.go b/perf/integration/generate_data.go
index 9019ca6..566c9ae 100644
--- a/perf/integration/generate_data.go
+++ b/perf/integration/generate_data.go
@@ -6,8 +6,8 @@
 import (
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"math/rand"
+	"os"
 
 	"go.skia.org/infra/go/sklog"
 	"go.skia.org/infra/perf/go/ingest/format"
@@ -70,7 +70,7 @@
 		if err != nil {
 			sklog.Fatal(err)
 		}
-		if err := ioutil.WriteFile(fmt.Sprintf("./data/demo_data_commit_%d.json", i+1), b, 0644); err != nil {
+		if err := os.WriteFile(fmt.Sprintf("./data/demo_data_commit_%d.json", i+1), b, 0644); err != nil {
 			sklog.Fatal(err)
 		}
 	}
diff --git a/proberk/go/proberk/proberk.go b/proberk/go/proberk/proberk.go
index 00b6e17..09e1453 100644
--- a/proberk/go/proberk/proberk.go
+++ b/proberk/go/proberk/proberk.go
@@ -11,7 +11,6 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"net/url"
 	"os"
@@ -145,12 +144,12 @@
 // gobPublicReposGood confirms the response matches the file contents stored in
 // expectations/gob.json.
 func gobPublicReposGood(r io.Reader, _ http.Header) bool {
-	gobb, err := ioutil.ReadFile(filepath.Join(*expectationsDir, "gob.json"))
+	gobb, err := os.ReadFile(filepath.Join(*expectationsDir, "gob.json"))
 	if err != nil {
 		sklog.Errorf("Failed to read probe expectation: %s", err)
 		return false
 	}
-	b, err := ioutil.ReadAll(r)
+	b, err := io.ReadAll(r)
 	if err != nil {
 		sklog.Errorf("Failed to read probe response: %s", err)
 		return false
diff --git a/proberk/go/types/types.go b/proberk/go/types/types.go
index 5edfd7c..9daac57b 100644
--- a/proberk/go/types/types.go
+++ b/proberk/go/types/types.go
@@ -5,7 +5,6 @@
 	"encoding/json"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 
 	_ "embed" // For embed functionality.
@@ -67,7 +66,7 @@
 func LoadFromJSONFile(ctx context.Context, filename string) (Probes, error) {
 	var probes Probes
 	err := util.WithReadFile(filename, func(r io.Reader) error {
-		document, err := ioutil.ReadAll(r)
+		document, err := io.ReadAll(r)
 		if err != nil {
 			return skerr.Wrap(err)
 		}
diff --git a/promk/go/backup-to-gcs/main.go b/promk/go/backup-to-gcs/main.go
index 0cd68ec..fcb5bbb 100644
--- a/promk/go/backup-to-gcs/main.go
+++ b/promk/go/backup-to-gcs/main.go
@@ -6,7 +6,7 @@
 	"context"
 	"flag"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"path"
 	"path/filepath"
 	"time"
@@ -32,7 +32,7 @@
 )
 
 func step(storageClient *storage.Client) error {
-	b, err := ioutil.ReadFile(*input)
+	b, err := os.ReadFile(*input)
 	if err != nil {
 		return fmt.Errorf("Failed to read input file: %s", err)
 	}
diff --git a/promk/go/genpromcrd/genpromcrd/genpromcrd.go b/promk/go/genpromcrd/genpromcrd/genpromcrd.go
index 9f7f7b8..71b943b 100644
--- a/promk/go/genpromcrd/genpromcrd/genpromcrd.go
+++ b/promk/go/genpromcrd/genpromcrd/genpromcrd.go
@@ -8,7 +8,6 @@
 	"fmt"
 	"io"
 	"io/fs"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -56,7 +55,7 @@
 func getAlertTargetsFromFilename(filename string) (AlertTargets, error) {
 	ret := AlertTargets{}
 	err := util.WithReadFile(filename, func(f io.Reader) error {
-		b, err := ioutil.ReadAll(f)
+		b, err := io.ReadAll(f)
 		if err != nil {
 			return err
 		}
diff --git a/promk/go/genpromcrd/genpromcrd/genpromcrd_test.go b/promk/go/genpromcrd/genpromcrd/genpromcrd_test.go
index a7f320b..e77197a 100644
--- a/promk/go/genpromcrd/genpromcrd/genpromcrd_test.go
+++ b/promk/go/genpromcrd/genpromcrd/genpromcrd_test.go
@@ -3,7 +3,7 @@
 package genpromcrd
 
 import (
-	"io/ioutil"
+	"io"
 	"os"
 	"path/filepath"
 	"strings"
@@ -107,7 +107,7 @@
 
 	err := w.Close()
 	require.NoError(t, err)
-	out, err := ioutil.ReadAll(r)
+	out, err := io.ReadAll(r)
 	require.NoError(t, err)
 
 	// We only expect a single file to be written.
@@ -131,7 +131,7 @@
 
 	newlyWrittenFilename := filepath.Join(tmpDir, "skia-infra-public/perf_appgroup_alerts.yml")
 	require.FileExists(t, newlyWrittenFilename)
-	b, err := ioutil.ReadFile(newlyWrittenFilename)
+	b, err := os.ReadFile(newlyWrittenFilename)
 	require.NoError(t, err)
 
 	expected := `# File is generated by genpromcrd. DO NOT EDIT.
diff --git a/promk/go/pushgateway/pushgateway_test.go b/promk/go/pushgateway/pushgateway_test.go
index 0bd9520..654b18e 100644
--- a/promk/go/pushgateway/pushgateway_test.go
+++ b/promk/go/pushgateway/pushgateway_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/http/httptest"
 	"testing"
@@ -17,7 +17,7 @@
 
 	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		if r.URL.Path == "/metrics/job/test_job" {
-			body, err := ioutil.ReadAll(r.Body)
+			body, err := io.ReadAll(r.Body)
 			require.NoError(t, err)
 			require.Equal(t, "test_metric_name test_metric_value\n", string(body))
 		} else {
diff --git a/scripts/make_dummy_staging_tasks/make_dummy_staging_tasks.go b/scripts/make_dummy_staging_tasks/make_dummy_staging_tasks.go
index 436a194..a5b158a 100644
--- a/scripts/make_dummy_staging_tasks/make_dummy_staging_tasks.go
+++ b/scripts/make_dummy_staging_tasks/make_dummy_staging_tasks.go
@@ -5,7 +5,6 @@
 	"encoding/json"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"sort"
 	"strings"
@@ -285,7 +284,7 @@
 		botCfgData += botSection
 		rangeStart += n
 	}
-	if err := ioutil.WriteFile(*botsCfg, []byte(botCfgData), os.ModePerm); err != nil {
+	if err := os.WriteFile(*botsCfg, []byte(botCfgData), os.ModePerm); err != nil {
 		sklog.Fatal(err)
 	}
 	sklog.Infof("Create bots with:\n$ go run ./go/gce/swarming/swarming_vm.go --dev --create --type=linux-micro --instances=%d-%d", botIdStart, rangeStart-1)
diff --git a/scripts/pubsub_recorder/pubsub_recorder.go b/scripts/pubsub_recorder/pubsub_recorder.go
index 61fb173..25a1dd6 100644
--- a/scripts/pubsub_recorder/pubsub_recorder.go
+++ b/scripts/pubsub_recorder/pubsub_recorder.go
@@ -7,7 +7,6 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"sync"
 	"time"
@@ -121,7 +120,7 @@
 func doPlayback(ctx context.Context, client *pubsub.Client, file string) {
 	topic := client.Topic(*topicName)
 	defer topic.Stop()
-	b, err := ioutil.ReadFile(file)
+	b, err := os.ReadFile(file)
 	if err != nil {
 		sklog.Fatal(err)
 	}
diff --git a/scripts/roll_recipe_deps/roll_recipe_deps.go b/scripts/roll_recipe_deps/roll_recipe_deps.go
index 3ed2430..77c72c1 100644
--- a/scripts/roll_recipe_deps/roll_recipe_deps.go
+++ b/scripts/roll_recipe_deps/roll_recipe_deps.go
@@ -28,7 +28,6 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"sort"
@@ -80,7 +79,7 @@
 // rollOnce performs a single recipe roll and returns the commits in the roll.
 // The result will be empty if the repo is up-to-date.
 func rollOnce(ctx context.Context, repoUrl, cwd string) (map[string][]string, error) {
-	tmpDir, err := ioutil.TempDir("", "recipe_roll_")
+	tmpDir, err := os.MkdirTemp("", "recipe_roll_")
 	if err != nil {
 		return nil, err
 	}
@@ -118,7 +117,7 @@
 // Returns the URL of the uploaded CL, if any.
 func rollRepo(ctx context.Context, repoUrl string) (string, error) {
 	sklog.Infof("  Creating checkout...")
-	tmpDir, err := ioutil.TempDir("", "recipe_roll_")
+	tmpDir, err := os.MkdirTemp("", "recipe_roll_")
 	if err != nil {
 		return "", err
 	}
diff --git a/scripts/run_on_swarming_bots/run_on_swarming_bots.go b/scripts/run_on_swarming_bots/run_on_swarming_bots.go
index 8952ec3..7e11069 100644
--- a/scripts/run_on_swarming_bots/run_on_swarming_bots.go
+++ b/scripts/run_on_swarming_bots/run_on_swarming_bots.go
@@ -4,7 +4,6 @@
 	"context"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -120,7 +119,7 @@
 		}
 
 		// Copy the script to the workdir.
-		casRoot, err := ioutil.TempDir(*workdir, "run_on_swarming_bots")
+		casRoot, err := os.MkdirTemp(*workdir, "run_on_swarming_bots")
 		if err != nil {
 			sklog.Fatal(err)
 		}
diff --git a/scripts/run_swarming_tasks_api/run_swarming_tasks_api.go b/scripts/run_swarming_tasks_api/run_swarming_tasks_api.go
index 4c2ea59..cb7b6ba 100644
--- a/scripts/run_swarming_tasks_api/run_swarming_tasks_api.go
+++ b/scripts/run_swarming_tasks_api/run_swarming_tasks_api.go
@@ -4,7 +4,6 @@
 	"context"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"sync"
@@ -206,7 +205,7 @@
 							continue
 						}
 						destFile := filepath.Join(outDir, fmt.Sprintf("%s-%s.txt", t.Request.Name, t.TaskId))
-						if err := ioutil.WriteFile(destFile, []byte(stdout.Output), 0644); err != nil {
+						if err := os.WriteFile(destFile, []byte(stdout.Output), 0644); err != nil {
 							sklog.Errorf("Could not write log to %s: %s", destFile, err)
 							continue
 						}
diff --git a/sk/go/asset/asset.go b/sk/go/asset/asset.go
index b3bf7f7..d8b1c00 100644
--- a/sk/go/asset/asset.go
+++ b/sk/go/asset/asset.go
@@ -6,7 +6,6 @@
 	"encoding/json"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"os"
 	os_exec "os/exec"
@@ -253,7 +252,7 @@
 
 	// Write the initial (empty) version file.
 	versionFile := filepath.Join(assetDir, versionFileBaseName)
-	if err := ioutil.WriteFile(versionFile, []byte{}, os.ModePerm); err != nil {
+	if err := os.WriteFile(versionFile, []byte{}, os.ModePerm); err != nil {
 		return skerr.Wrap(err)
 	}
 
@@ -266,7 +265,7 @@
 	read = strings.TrimSpace(read)
 	if read == "y" {
 		creationScript := filepath.Join(assetDir, creationScriptBaseName)
-		if err := ioutil.WriteFile(creationScript, []byte(creationScriptInitialContents), os.ModePerm); err != nil {
+		if err := os.WriteFile(creationScript, []byte(creationScriptInitialContents), os.ModePerm); err != nil {
 			return skerr.Wrap(err)
 		}
 		fmt.Println(fmt.Sprintf("Created %s; you will need to add implementation before uploading the asset.", creationScript))
@@ -376,7 +375,7 @@
 		if src != "" {
 			return skerr.Fmt("Target directory is not supplied when using a creation script.")
 		}
-		src, err = ioutil.TempDir("", "")
+		src, err = os.MkdirTemp("", "")
 		if err != nil {
 			return skerr.Wrap(err)
 		}
@@ -537,7 +536,7 @@
 	if err != nil {
 		return -1, skerr.Wrap(err)
 	}
-	b, err := ioutil.ReadFile(versionFile)
+	b, err := os.ReadFile(versionFile)
 	if err != nil {
 		if os.IsNotExist(err) {
 			return -1, skerr.Wrapf(err, "unknown asset %q", name)
@@ -557,7 +556,7 @@
 	if err != nil {
 		return skerr.Wrap(err)
 	}
-	if err := ioutil.WriteFile(versionFile, []byte(strconv.Itoa(version)), os.ModePerm); err != nil {
+	if err := os.WriteFile(versionFile, []byte(strconv.Itoa(version)), os.ModePerm); err != nil {
 		return skerr.Wrap(err)
 	}
 	return nil
diff --git a/sk/go/release-branch/release-branch.go b/sk/go/release-branch/release-branch.go
index 2ae5c36..83ff7f8 100644
--- a/sk/go/release-branch/release-branch.go
+++ b/sk/go/release-branch/release-branch.go
@@ -5,7 +5,6 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -415,7 +414,7 @@
 		return nil, skerr.Wrap(err)
 	}
 	baseCommit := baseCommitInfo.Hash
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	if err != nil {
 		return nil, skerr.Wrap(err)
 	}
@@ -459,7 +458,7 @@
 	// the CQ. Also attempt to match the whitespace of the original files, to
 	// help prevent conflicts during cherry-picks.
 	newJobsContents = jobsJSONReplaceRegex.ReplaceAll(newJobsContents, jobsJSONReplaceContents)
-	if err := ioutil.WriteFile(filepath.Join(co.Dir(), jobsJSONFile), newJobsContents, os.ModePerm); err != nil {
+	if err := os.WriteFile(filepath.Join(co.Dir(), jobsJSONFile), newJobsContents, os.ModePerm); err != nil {
 		return nil, skerr.Wrapf(err, "failed to write %s", jobsJSONFile)
 	}
 
diff --git a/skfe/go/update_probers/main.go b/skfe/go/update_probers/main.go
index e4107a0..8801f5d 100644
--- a/skfe/go/update_probers/main.go
+++ b/skfe/go/update_probers/main.go
@@ -6,7 +6,7 @@
 import (
 	"flag"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"sort"
 	"strings"
 
@@ -83,7 +83,7 @@
 	}
 
 	// Rewrite the probers file.
-	if err := ioutil.WriteFile(*probersFilename, []byte(probers.StringIndent("", "  ")), 0644); err != nil {
+	if err := os.WriteFile(*probersFilename, []byte(probers.StringIndent("", "  ")), 0644); err != nil {
 		sklog.Fatal(err)
 	}
 }
diff --git a/skolo/go/censustaker/censustaker_test.go b/skolo/go/censustaker/censustaker_test.go
index e64a0d7..8826fbc 100644
--- a/skolo/go/censustaker/censustaker_test.go
+++ b/skolo/go/censustaker/censustaker_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"fmt"
-	"io/ioutil"
+	"io"
 	"os"
 	"regexp"
 	"testing"
@@ -87,7 +87,7 @@
 	require.Equal(t, []string{"sshpass", "-p", fakePassword, "ssh", "power@192.168.1.117"}, args)
 
 	// We expect the command to be sent over standard in once the ssh connection is established.
-	input, err := ioutil.ReadAll(os.Stdin)
+	input, err := io.ReadAll(os.Stdin)
 	require.NoError(t, err)
 
 	assert.Equal(t, "enable\nshow mac-addr-table all\nmmmmmmmmm\n", string(input))
diff --git a/skolo/go/file-backup/main.go b/skolo/go/file-backup/main.go
index 903b25e..ed81b8b 100644
--- a/skolo/go/file-backup/main.go
+++ b/skolo/go/file-backup/main.go
@@ -9,7 +9,6 @@
 	"context"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"time"
@@ -44,7 +43,7 @@
 	sklog.Infof("Running backup to %s", *gceFolder)
 	if *remoteFilePath != "" {
 		// If backing up a remote file, copy it here first, then pretend it is a local file.
-		dir, err := ioutil.TempDir("", "backups")
+		dir, err := os.MkdirTemp("", "backups")
 		if err != nil {
 			sklog.Fatalf("Could not create temp directory %s: %s", dir, err)
 		}
diff --git a/skolo/go/powercycle/mpower_test.go b/skolo/go/powercycle/mpower_test.go
index 7ecde55..55f8b2a 100644
--- a/skolo/go/powercycle/mpower_test.go
+++ b/skolo/go/powercycle/mpower_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"io"
 	"os"
 	"testing"
 	"time"
@@ -47,7 +47,7 @@
 	require.Equal(t, []string{"ssh", "-oKexAlgorithms=+diffie-hellman-group1-sha1", "-T", "ubnt@192.168.1.117"}, args)
 
 	// We expect the command to be sent over standard in once the ssh connection is established.
-	input, err := ioutil.ReadAll(os.Stdin)
+	input, err := io.ReadAll(os.Stdin)
 	require.NoError(t, err)
 
 	assert.Equal(t, "echo 0 > /proc/power/relay7\n", string(input))
@@ -64,7 +64,7 @@
 	require.Equal(t, []string{"ssh", "-oKexAlgorithms=+diffie-hellman-group1-sha1", "-T", "ubnt@192.168.1.117"}, args)
 
 	// We expect the command to be sent over standard in once the ssh connection is established.
-	input, err := ioutil.ReadAll(os.Stdin)
+	input, err := io.ReadAll(os.Stdin)
 	require.NoError(t, err)
 
 	assert.Equal(t, "echo 1 > /proc/power/relay7\n", string(input))
diff --git a/skolo/go/powercycle/powercycle.go b/skolo/go/powercycle/powercycle.go
index c3917ca..455125e 100644
--- a/skolo/go/powercycle/powercycle.go
+++ b/skolo/go/powercycle/powercycle.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"os"
 	"sort"
 	"time"
 
@@ -208,7 +208,7 @@
 
 func readConfig(path string) (config, error) {
 	conf := config{}
-	jsonBytes, err := ioutil.ReadFile(path)
+	jsonBytes, err := os.ReadFile(path)
 	if err != nil {
 		return conf, skerr.Wrapf(err, "reading %s", path)
 	}
diff --git a/skolo/go/powercycle_server_ansible/main_test.go b/skolo/go/powercycle_server_ansible/main_test.go
index 4c7e857..465afdb 100644
--- a/skolo/go/powercycle_server_ansible/main_test.go
+++ b/skolo/go/powercycle_server_ansible/main_test.go
@@ -4,7 +4,7 @@
 	"context"
 	"encoding/json"
 	"errors"
-	"io/ioutil"
+	"io"
 	"net/http"
 	"net/http/httptest"
 	"net/url"
@@ -204,7 +204,7 @@
 		},
 	}
 	u, called, client := setupForTest(t, func(w http.ResponseWriter, r *http.Request) {
-		actual, err := ioutil.ReadAll(r.Body)
+		actual, err := io.ReadAll(r.Body)
 		require.NoError(t, err)
 		expected, err := json.Marshal(body)
 		require.NoError(t, err)
diff --git a/skolo/go/router_backup_ansible/main.go b/skolo/go/router_backup_ansible/main.go
index e71d81b..43702f3 100644
--- a/skolo/go/router_backup_ansible/main.go
+++ b/skolo/go/router_backup_ansible/main.go
@@ -7,7 +7,6 @@
 	"context"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"time"
@@ -42,7 +41,7 @@
 	sklog.Infof("Running backup to %s", *gceFolder)
 	if *remoteFilePath != "" {
 		// If backing up a remote file, copy it here first, then pretend it is a local file.
-		dir, err := ioutil.TempDir("", "backups")
+		dir, err := os.MkdirTemp("", "backups")
 		if err != nil {
 			sklog.Fatalf("Could not create temp directory %s: %s", dir, err)
 		}
diff --git a/skolo/go/skmetadata/skmetadata.go b/skolo/go/skmetadata/skmetadata.go
index dedd190..192b5a3 100644
--- a/skolo/go/skmetadata/skmetadata.go
+++ b/skolo/go/skmetadata/skmetadata.go
@@ -6,9 +6,9 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"net"
 	"net/http"
+	"os"
 	"strings"
 	"sync"
 	"time"
@@ -107,7 +107,7 @@
 // readTokenFromFile opens the file provided to the constructor and reads a token from it.
 func (t *ServiceAccountToken) readTokenFromFile() (*oauth2.Token, error) {
 	// Read the token from the file.
-	contents, err := ioutil.ReadFile(t.filename)
+	contents, err := os.ReadFile(t.filename)
 	if err != nil {
 		return nil, err
 	}
diff --git a/skottie/go/skottie/skottie.go b/skottie/go/skottie/skottie.go
index a6b207d..4b81a3d 100644
--- a/skottie/go/skottie/skottie.go
+++ b/skottie/go/skottie/skottie.go
@@ -11,7 +11,6 @@
 	"fmt"
 	"html/template"
 	"io"
-	"io/ioutil"
 	"mime"
 	"net/http"
 	"path/filepath"
@@ -431,7 +430,7 @@
 		return skerr.Wrapf(err, "unziping lottie.json %s", req.Filename)
 	}
 
-	lottieBytes, err := ioutil.ReadAll(fr)
+	lottieBytes, err := io.ReadAll(fr)
 	if err := json.Unmarshal(lottieBytes, &req.Lottie); err != nil {
 		return skerr.Wrapf(err, "lottie.json was invalid JSON: %s", req.Filename)
 	}
diff --git a/skottie/go/skottie/skottie_test.go b/skottie/go/skottie/skottie_test.go
index 2ea24f2..d57bf03 100644
--- a/skottie/go/skottie/skottie_test.go
+++ b/skottie/go/skottie/skottie_test.go
@@ -5,7 +5,6 @@
 	"image"
 	"image/png"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"net/http/httptest"
 	"path/filepath"
@@ -47,7 +46,7 @@
 	resp := w.Result()
 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 	assert.Equal(t, jsonContentType, resp.Header.Get(contentTypeHeader))
-	respBody, err := ioutil.ReadAll(resp.Body)
+	respBody, err := io.ReadAll(resp.Body)
 	require.NoError(t, err)
 	// spot check the return body
 	assert.Contains(t, string(respBody), `"hash":"c54ac366e2c358cab4e6431cb47d6178"`)
@@ -101,7 +100,7 @@
 	resp := w.Result()
 	assert.Equal(t, http.StatusOK, resp.StatusCode)
 	assert.Equal(t, jsonContentType, resp.Header.Get(contentTypeHeader))
-	respBody, err := ioutil.ReadAll(resp.Body)
+	respBody, err := io.ReadAll(resp.Body)
 	require.NoError(t, err)
 	// spot check the return body
 	assert.Contains(t, string(respBody), `"hash":"5f0e05cf5594b23cc98a1a31693a377c"`)
diff --git a/status/go/incremental/incremental_test.go b/status/go/incremental/incremental_test.go
index cc5387d..e5ebf29 100644
--- a/status/go/incremental/incremental_test.go
+++ b/status/go/incremental/incremental_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"os"
 	"testing"
 	"time"
 
@@ -26,7 +26,7 @@
 	ctx := cipd_git.UseGitFinder(context.Background())
 	gb := git_testutils.GitInit(t, ctx)
 	c0 := gb.CommitGen(ctx, "placeholder")
-	workdir, err := ioutil.TempDir("", "")
+	workdir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	repo, err := repograph.NewLocalGraph(ctx, gb.Dir(), workdir)
 	require.NoError(t, err)
diff --git a/task_driver/go/db/shared_tests/shared_tests.go b/task_driver/go/db/shared_tests/shared_tests.go
index 6b9acdb..26a161b 100644
--- a/task_driver/go/db/shared_tests/shared_tests.go
+++ b/task_driver/go/db/shared_tests/shared_tests.go
@@ -8,8 +8,8 @@
 	"context"
 	"encoding/json"
 	"io"
-	"io/ioutil"
 	"math/rand"
+	"os"
 	"path"
 	"time"
 
@@ -99,7 +99,7 @@
 // Verify that messages can arrive in any order with the same result.
 func TestMessageOrdering(t sktest.TestingT, d db.DB) {
 	ctx := context.Background()
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, wd)
 	testDataFile := path.Join(wd, TEST_DATA_FILENAME)
diff --git a/task_driver/go/lib/os_steps/os_steps.go b/task_driver/go/lib/os_steps/os_steps.go
index 2aa589d..0ac6e41 100644
--- a/task_driver/go/lib/os_steps/os_steps.go
+++ b/task_driver/go/lib/os_steps/os_steps.go
@@ -81,12 +81,12 @@
 	return rv, err
 }
 
-// ReadFile is a wrapper for ioutil.ReadFile.
+// ReadFile is a wrapper for os.ReadFile.
 func ReadFile(ctx context.Context, path string) ([]byte, error) {
 	var rv []byte
 	err := td.Do(ctx, td.Props(fmt.Sprintf("Read %s", path)).Infra(), func(context.Context) error {
 		var err error
-		rv, err = ioutil.ReadFile(path)
+		rv, err = os.ReadFile(path)
 		return err
 	})
 	return rv, err
@@ -110,10 +110,10 @@
 	})
 }
 
-// WriteFile is a wrapper for ioutil.WriteFile.
+// WriteFile is a wrapper for os.WriteFile.
 func WriteFile(ctx context.Context, path string, data []byte, perm os.FileMode) error {
 	return td.Do(ctx, td.Props(fmt.Sprintf("Write %s", path)).Infra(), func(context.Context) error {
-		return ioutil.WriteFile(path, data, perm)
+		return os.WriteFile(path, data, perm)
 	})
 }
 
diff --git a/task_driver/go/td/step.go b/task_driver/go/td/step.go
index 3380c56..fa4eb42 100644
--- a/task_driver/go/td/step.go
+++ b/task_driver/go/td/step.go
@@ -4,7 +4,6 @@
 	"context"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/http"
 	"net/url"
 	"os"
@@ -270,7 +269,7 @@
 // writing from a test program.
 func NewFileStream(ctx context.Context, name string, severity Severity) (*FileStream, error) {
 	w := NewLogStream(ctx, name, severity)
-	f, err := ioutil.TempFile("", "log")
+	f, err := os.CreateTemp("", "log")
 	if err != nil {
 		return nil, fmt.Errorf("Failed to create file-based log stream; failed to create log file: %s", err)
 	}
diff --git a/task_driver/go/td/testutil.go b/task_driver/go/td/testutil.go
index 8ad56c5..732800f 100644
--- a/task_driver/go/td/testutil.go
+++ b/task_driver/go/td/testutil.go
@@ -2,7 +2,6 @@
 
 import (
 	"context"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 
@@ -22,7 +21,7 @@
 // StartTestRun returns a root-level Step to be used for testing. This is
 // an alternative so that we don't need to call Init() in testing.
 func StartTestRun(t sktest.TestingT) *TestingRun {
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	output := filepath.Join(wd, "output.json")
 	report := newReportReceiver(output)
diff --git a/task_scheduler/go/cacher/cacher_test.go b/task_scheduler/go/cacher/cacher_test.go
index fabadc4..7413bf8 100644
--- a/task_scheduler/go/cacher/cacher_test.go
+++ b/task_scheduler/go/cacher/cacher_test.go
@@ -2,7 +2,7 @@
 
 import (
 	"context"
-	"io/ioutil"
+	"os"
 	"testing"
 
 	"github.com/stretchr/testify/mock"
@@ -30,7 +30,7 @@
 		Revision: rev,
 	}
 
-	wd, err := ioutil.TempDir("", "")
+	wd, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	repos, err := repograph.NewLocalMap(ctx, []string{gb.RepoUrl()}, wd)
 	require.NoError(t, err)
diff --git a/task_scheduler/go/db/testutil.go b/task_scheduler/go/db/testutil.go
index a2a414a..7f9bbeb 100644
--- a/task_scheduler/go/db/testutil.go
+++ b/task_scheduler/go/db/testutil.go
@@ -3,8 +3,8 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"net/url"
+	"os"
 	"sort"
 	"time"
 
@@ -1453,7 +1453,7 @@
 			task.Repo = repoUrl
 			require.NoError(t, db.PutTask(ctx, task))
 		}
-		tmp, err := ioutil.TempDir("", "")
+		tmp, err := os.MkdirTemp("", "")
 		require.NoError(t, err)
 		repo, err := repograph.NewLocalGraph(ctx, gb.Dir(), tmp)
 		require.NoError(t, err)
diff --git a/task_scheduler/go/job_creation/job_creation_test.go b/task_scheduler/go/job_creation/job_creation_test.go
index a41ad2b..b2dc24d 100644
--- a/task_scheduler/go/job_creation/job_creation_test.go
+++ b/task_scheduler/go/job_creation/job_creation_test.go
@@ -3,8 +3,8 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
 	"math"
+	"os"
 	"testing"
 	"time"
 
@@ -43,7 +43,7 @@
 	ctx, gb, _, _ := tcc_testutils.SetupTestRepo(t)
 	ctx, cancel := context.WithCancel(ctx)
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	d := memory.NewInMemoryDB()
@@ -276,7 +276,7 @@
 	ctx, cancel := context.WithCancel(ctx)
 	defer cancel()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 	swarmingClient := swarming_testutils.NewTestClient()
diff --git a/task_scheduler/go/parse_task_cfg/main.go b/task_scheduler/go/parse_task_cfg/main.go
index d35f613..e8e7b14 100644
--- a/task_scheduler/go/parse_task_cfg/main.go
+++ b/task_scheduler/go/parse_task_cfg/main.go
@@ -6,7 +6,7 @@
 
 import (
 	"flag"
-	"io/ioutil"
+	"os"
 
 	"go.skia.org/infra/go/common"
 	"go.skia.org/infra/go/sklog"
@@ -20,7 +20,7 @@
 func main() {
 	common.Init()
 
-	b, err := ioutil.ReadFile(*cfgFile)
+	b, err := os.ReadFile(*cfgFile)
 	if err != nil {
 		sklog.Fatal(err)
 	}
diff --git a/task_scheduler/go/scheduling/perftest/perftest.go b/task_scheduler/go/scheduling/perftest/perftest.go
index dc8bece..5f8e64a 100644
--- a/task_scheduler/go/scheduling/perftest/perftest.go
+++ b/task_scheduler/go/scheduling/perftest/perftest.go
@@ -10,7 +10,6 @@
 	"flag"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"math"
 	"net/http"
 	"os"
@@ -115,7 +114,7 @@
 	fakeFile := path.Join(repoDir, "fakefile.txt")
 	for i := 0; i < numCommits; i++ {
 		title := fmt.Sprintf("Fake #%d", i)
-		assertNoError(ioutil.WriteFile(fakeFile, []byte(title), os.ModePerm))
+		assertNoError(os.WriteFile(fakeFile, []byte(title), os.ModePerm))
 		_, err = gd.Git(ctx, "add", fakeFile)
 		assertNoError(err)
 		commit(ctx, repoDir, title)
@@ -125,7 +124,7 @@
 }
 
 func addFile(ctx context.Context, repoDir, subPath, contents string) {
-	assertNoError(ioutil.WriteFile(path.Join(repoDir, subPath), []byte(contents), os.ModePerm))
+	assertNoError(os.WriteFile(path.Join(repoDir, subPath), []byte(contents), os.ModePerm))
 	_, err := git.GitDir(repoDir).Git(ctx, "add", subPath)
 	assertNoError(err)
 }
@@ -153,7 +152,7 @@
 	common.Init()
 
 	// Create a repo with one commit.
-	workdir, err := ioutil.TempDir("", "")
+	workdir, err := os.MkdirTemp("", "")
 	assertNoError(err)
 	defer func() {
 		if err := os.RemoveAll(workdir); err != nil {
@@ -174,7 +173,7 @@
 	assertNoError(err)
 
 	// Write some files.
-	assertNoError(ioutil.WriteFile(path.Join(workdir, ".gclient"), []byte("placeholder"), os.ModePerm))
+	assertNoError(os.WriteFile(path.Join(workdir, ".gclient"), []byte("placeholder"), os.ModePerm))
 	addFile(ctx, repoDir, "a.txt", "placeholder2")
 	addFile(ctx, repoDir, "somefile.txt", "placeholder3")
 	infraBotsSubDir := path.Join("infra", "bots")
diff --git a/task_scheduler/go/scheduling/task_scheduler_test.go b/task_scheduler/go/scheduling/task_scheduler_test.go
index b9562a1..f41bbe2 100644
--- a/task_scheduler/go/scheduling/task_scheduler_test.go
+++ b/task_scheduler/go/scheduling/task_scheduler_test.go
@@ -5,8 +5,8 @@
 	"encoding/json"
 	"errors"
 	"fmt"
-	"io/ioutil"
 	"math"
+	"os"
 	"path"
 	"sort"
 	"strings"
@@ -263,7 +263,7 @@
 
 	ctx, cancel := context.WithCancel(context.Background())
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	d := memory.NewInMemoryDB()
@@ -2301,7 +2301,7 @@
 func testMultipleCandidatesBackfillingEachOtherSetup(t *testing.T) (context.Context, *mem_git.MemGit, db.DB, *TaskScheduler, *swarming_testutils.TestClient, []string, func(*types.Task), *specs.TasksCfg, func()) {
 
 	ctx, cancel := context.WithCancel(context.Background())
-	workdir, err := ioutil.TempDir("", "")
+	workdir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	// Setup the scheduler.
diff --git a/task_scheduler/go/specs/cmd/validate-tasks-json/main.go b/task_scheduler/go/specs/cmd/validate-tasks-json/main.go
index 01bfc26..e4d1743 100644
--- a/task_scheduler/go/specs/cmd/validate-tasks-json/main.go
+++ b/task_scheduler/go/specs/cmd/validate-tasks-json/main.go
@@ -1,7 +1,6 @@
 package main
 
 import (
-	"io/ioutil"
 	"log"
 	"os"
 
@@ -14,7 +13,7 @@
 		log.Fatal("Specify at least one tasks.json to validate.")
 	}
 	for _, tasksJSON := range tasksJSONs {
-		contents, err := ioutil.ReadFile(tasksJSON)
+		contents, err := os.ReadFile(tasksJSON)
 		if err != nil {
 			log.Fatal(err)
 		}
diff --git a/task_scheduler/go/specs/helpers.go b/task_scheduler/go/specs/helpers.go
index 7699c76..8e23001 100644
--- a/task_scheduler/go/specs/helpers.go
+++ b/task_scheduler/go/specs/helpers.go
@@ -8,7 +8,6 @@
 	"bytes"
 	"flag"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"reflect"
@@ -194,7 +193,7 @@
 		assetsDir = filepath.Join(b.root, "infra", "bots", "assets")
 	}
 	versionFile := filepath.Join(assetsDir, assetName, "VERSION")
-	contents, err := ioutil.ReadFile(versionFile)
+	contents, err := os.ReadFile(versionFile)
 	if err != nil {
 		return nil, err
 	}
@@ -267,7 +266,7 @@
 	outFile := filepath.Join(b.root, TASKS_CFG_FILE)
 	if *test {
 		// Don't write the file; read it and compare.
-		expect, err := ioutil.ReadFile(outFile)
+		expect, err := os.ReadFile(outFile)
 		if err != nil {
 			return err
 		}
@@ -295,7 +294,7 @@
 `, diff)
 		}
 	} else {
-		if err := ioutil.WriteFile(outFile, enc, os.ModePerm); err != nil {
+		if err := os.WriteFile(outFile, enc, os.ModePerm); err != nil {
 			return err
 		}
 	}
diff --git a/task_scheduler/go/specs/specs.go b/task_scheduler/go/specs/specs.go
index 895eebd..2a41227 100644
--- a/task_scheduler/go/specs/specs.go
+++ b/task_scheduler/go/specs/specs.go
@@ -4,7 +4,6 @@
 	"bytes"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"path"
 	"sort"
@@ -152,7 +151,7 @@
 
 // ReadTasksCfg reads the task cfg file from the given dir and returns it.
 func ReadTasksCfg(repoDir string) (*TasksCfg, error) {
-	contents, err := ioutil.ReadFile(path.Join(repoDir, TASKS_CFG_FILE))
+	contents, err := os.ReadFile(path.Join(repoDir, TASKS_CFG_FILE))
 	if err != nil {
 		// A nonexistent tasks.json file is valid; return an empty config.
 		if os.IsNotExist(err) {
@@ -169,7 +168,7 @@
 	if err != nil {
 		return err
 	}
-	return ioutil.WriteFile(path.Join(repoDir, TASKS_CFG_FILE), enc, os.ModePerm)
+	return os.WriteFile(path.Join(repoDir, TASKS_CFG_FILE), enc, os.ModePerm)
 }
 
 // CommitQueueJobConfig describes how a job should run on the Commit Queue.
diff --git a/task_scheduler/go/syncer/syncer.go b/task_scheduler/go/syncer/syncer.go
index 4c972a3..9fd40ce 100644
--- a/task_scheduler/go/syncer/syncer.go
+++ b/task_scheduler/go/syncer/syncer.go
@@ -4,7 +4,6 @@
 	"context"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"path"
 	"path/filepath"
@@ -80,7 +79,7 @@
 func (s *Syncer) TempGitRepo(ctx context.Context, rs types.RepoState, fn func(*git.TempCheckout) error) error {
 	rvErr := make(chan error)
 	s.queue <- func(workerId int) {
-		tmp, err2 := ioutil.TempDir("", "")
+		tmp, err2 := os.MkdirTemp("", "")
 		if err2 != nil {
 			rvErr <- err2
 			return
diff --git a/task_scheduler/go/syncer/syncer_manual_test.go b/task_scheduler/go/syncer/syncer_manual_test.go
index 4b11c23..0796fc1 100644
--- a/task_scheduler/go/syncer/syncer_manual_test.go
+++ b/task_scheduler/go/syncer/syncer_manual_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"errors"
-	"io/ioutil"
+	"os"
 	"strings"
 	"testing"
 
@@ -42,7 +42,7 @@
 	ctx, gb, c1, _ := tcc_testutils.SetupTestRepo(t)
 	defer gb.Cleanup()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
@@ -77,7 +77,7 @@
 	ctx, gb, c1, _ := tcc_testutils.SetupTestRepo(t)
 	defer gb.Cleanup()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
diff --git a/task_scheduler/go/syncer/syncer_test.go b/task_scheduler/go/syncer/syncer_test.go
index 7541b59..eb487cf 100644
--- a/task_scheduler/go/syncer/syncer_test.go
+++ b/task_scheduler/go/syncer/syncer_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"fmt"
-	"io/ioutil"
+	"os"
 	"path"
 	"strings"
 	"sync"
@@ -37,7 +37,7 @@
 }
 
 func tempGitRepoGclientTests(ctx context.Context, t *testing.T, cases map[types.RepoState]error) {
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 	// Skip download-topics in gclient calls to avoid that network call.
@@ -126,7 +126,7 @@
 	ctx, gb, c1, _ := tcc_testutils.SetupTestRepo(t)
 	defer gb.Cleanup()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
diff --git a/task_scheduler/go/task_cfg_cache/task_cfg_cache_test.go b/task_scheduler/go/task_cfg_cache/task_cfg_cache_test.go
index d99748a..9c2d1c2 100644
--- a/task_scheduler/go/task_cfg_cache/task_cfg_cache_test.go
+++ b/task_scheduler/go/task_cfg_cache/task_cfg_cache_test.go
@@ -3,7 +3,7 @@
 import (
 	"context"
 	"errors"
-	"io/ioutil"
+	"os"
 	"strings"
 	"testing"
 	"time"
@@ -23,7 +23,7 @@
 	ctx, gb, c1, c2 := tu.SetupTestRepo(t)
 	defer gb.Cleanup()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
@@ -100,7 +100,7 @@
 	ctx, gb, c1, c2 := tu.SetupTestRepo(t)
 	defer gb.Cleanup()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
@@ -150,7 +150,7 @@
 	ctx, gb, c1, c2 := tu.SetupTestRepo(t)
 	defer gb.Cleanup()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
@@ -219,7 +219,7 @@
 	ctx, gb, r1, _ := tu.SetupTestRepo(t)
 	defer gb.Cleanup()
 
-	tmp, err := ioutil.TempDir("", "")
+	tmp, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 	defer testutils.RemoveAll(t, tmp)
 
diff --git a/task_scheduler/go/tryjobs/utils_test.go b/task_scheduler/go/tryjobs/utils_test.go
index 72d8589..c950db7 100644
--- a/task_scheduler/go/tryjobs/utils_test.go
+++ b/task_scheduler/go/tryjobs/utils_test.go
@@ -4,7 +4,6 @@
 	"context"
 	"encoding/json"
 	"fmt"
-	"io/ioutil"
 	"math/rand"
 	"os"
 	"path"
@@ -134,7 +133,7 @@
 	gb2.CommitGen(ctx, "somefile")
 
 	// Create repo map.
-	tmpDir, err := ioutil.TempDir("", "")
+	tmpDir, err := os.MkdirTemp("", "")
 	require.NoError(t, err)
 
 	rm, err := repograph.NewLocalMap(ctx, []string{gb.RepoUrl(), gb2.RepoUrl()}, tmpDir)