# How to Manage Multiple CAs Using the CAROOT Environment Variable in mkcert

> Learn to manage multiple CAs with mkcert by setting the CAROOT environment variable for isolated certificate management across projects and testing environments.

- Repository: [Filippo Valsorda/mkcert](https://github.com/FiloSottile/mkcert)
- Tags: how-to-guide
- Published: 2026-03-05

---

**Set the `CAROOT` environment variable to a custom directory path before running mkcert to isolate certificate authorities for different projects or testing environments.**

The `CAROOT` environment variable in mkcert (FiloSottile/mkcert) controls where the tool stores its root CA files (`rootCA.pem` and `rootCA-key.pem`). By default, mkcert places these files in an OS-specific data directory, but overriding this location enables you to maintain completely independent certificate authorities for distinct development contexts or CI pipelines.

## Understanding the CAROOT Mechanism

In [`main.go`](https://github.com/FiloSottile/mkcert/blob/main/main.go), the `getCAROOT()` function determines the storage location for CA files by first checking for an environment variable override:

```go
func getCAROOT() string {
    if env := os.Getenv("CAROOT"); env != "" {
        return env
    }
    // Falls back to OS-specific default directory...
}

```

When `CAROOT` is set, mkcert stores the `m.CAROOT` string in its internal struct and passes this path to every helper function that reads or writes CA files, including `loadCA()` and `newCA()` in [`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go), as well as the platform-specific truststore installers ([`truststore_linux.go`](https://github.com/FiloSottile/mkcert/blob/main/truststore_linux.go), [`truststore_darwin.go`](https://github.com/FiloSottile/mkcert/blob/main/truststore_darwin.go), [`truststore_windows.go`](https://github.com/FiloSottile/mkcert/blob/main/truststore_windows.go), etc.). This design ensures that all subsequent operations—whether installing the CA to system trust stores or generating leaf certificates—operate exclusively within the specified directory.

## Creating Isolated Certificate Authorities

Because mkcert generates the CA files (`rootCA.pem` and `rootCA-key.pem`) on first run if they do not exist, setting a unique `CAROOT` for each project creates fully separate trust anchors.

### Project-Specific CA Setup

To establish an isolated CA for a single project:

```bash

# Define a private directory for this project's CA

export CAROOT="${HOME}/.mkcert-myproject"

# Generate the CA and install it (creates rootCA.pem and rootCA-key.pem)

mkcert -install

```

After running `-install`, mkcert places the CA certificate and key in `${HOME}/.mkcert-myproject/`. This CA remains independent from your default mkcert CA stored in the standard OS data directory.

### Generating Certificates with a Custom CAROOT

With `CAROOT` exported, all certificate generation commands use the isolated authority:

```bash

# Still using the custom CAROOT from above

mkcert example.test localhost 127.0.0.1

```

The resulting `example.test+2.pem` and `example.test+2-key.pem` files are signed by the CA in `${HOME}/.mkcert-myproject/`, not your global default CA.

## Managing Multiple CAs Simultaneously

You can operate multiple independent CAs in parallel by switching the environment variable between commands. This is useful for testing applications that validate certificates against different trust anchors or for maintaining separate PKI hierarchies for different microservices.

```bash

# Use the default CA location

unset CAROOT
mkcert -install
mkcert myapp.local

# Switch to an alternative CA in /tmp

export CAROOT="/tmp/alt-ca"
mkcert -install
mkcert -cert-file alt-cert.pem -key-file alt-key.pem otherapp.local

```

Each set of certificates trusts only the CA that resides in its respective `CAROOT` directory. The two CAs do not interfere with each other, and you can uninstall either independently using `mkcert -uninstall` while its specific `CAROOT` is set.

## Distributing Custom CAs Across Systems

The `CAROOT` variable also simplifies deploying a development CA to remote servers or Docker containers. Instead of regenerating a new CA on each system, copy the existing root certificate and initialize the remote environment with the same `CAROOT` structure:

```bash

# On the source machine: copy the CA certificate

cp "$(mkcert -CAROOT)/rootCA.pem" /tmp/ca-copy.pem

# On the remote host

export CAROOT="/etc/mkcert-remote"
mkdir -p "$CAROOT"
mv /tmp/ca-copy.pem "$CAROOT/rootCA.pem"
mkcert -install

```

This workflow, documented in the mkcert README under "Installing the CA on other systems," ensures that the remote system trusts exactly the same root authority as your local development environment.

## Summary

- **`CAROOT` overrides the default storage location** for `rootCA.pem` and `rootCA-key.pem`, as implemented in [`main.go`](https://github.com/FiloSottile/mkcert/blob/main/main.go) and referenced throughout [`cert.go`](https://github.com/FiloSottile/mkcert/blob/main/cert.go) and `truststore_*.go`.
- **Each unique directory represents an independent CA**, allowing per-project or per-environment isolation without code changes.
- **Switching contexts requires only changing the environment variable** before invoking mkcert commands.
- **CAs created with custom `CAROOT` values can be shared** across systems by copying the certificate files and setting the same path on the target machine.

## Frequently Asked Questions

### What is the default CAROOT location when the variable is not set?

When `CAROOT` is unset, mkcert derives the location from OS-specific data directories: `$HOME/.local/share/mkcert` on Linux, `$HOME/Library/Application Support/mkcert` on macOS, and `%LOCALAPPDATA%\mkcert` on Windows. The `getCAROOT()` function in [`main.go`](https://github.com/FiloSottile/mkcert/blob/main/main.go) handles this fallback logic after checking for the environment variable.

### Can I switch between multiple CAs without reinstalling mkcert globally?

Yes. Simply change the `CAROOT` environment variable between commands. Each invocation of mkcert operates only on the CA files present in the currently specified directory. You can generate certificates from CA "A", then immediately switch to CA "B" by exporting a different path, without affecting the system trust store entries created by previous `-install` commands.

### How do I completely remove a CA created with a custom CAROOT?

Run `mkcert -uninstall` while the specific `CAROOT` is exported. This removes the CA certificate from all system trust stores (Java, NSS, and OS stores) via the platform-specific `truststore_*.go` implementations, and then you can safely delete the directory contents including `rootCA.pem` and `rootCA-key.pem`.

### Does setting CAROOT affect where leaf certificates are saved?

No. The `CAROOT` variable only controls the location of the root CA files. Leaf certificates generated by `mkcert` are always saved to the current working directory (or paths specified by `-cert-file` and `-key-file` flags) regardless of where the CA is stored.