How to Use mkcert Certificates with Node.js Using NODE_EXTRA_CA_CERTS
Set the NODE_EXTRA_CA_CERTS environment variable to the path of mkcert's rootCA.pem file to make Node.js trust locally-generated development certificates.
When developing applications with Node.js, you often need HTTPS for local testing. While mkcert (by FiloSottile) creates a local Certificate Authority and installs it into your operating system's trust store, Node.js maintains its own hardcoded list of trusted CAs and ignores the system root store by design. To bridge this gap, you must explicitly point Node.js to mkcert's root certificate using the NODE_EXTRA_CA_CERTS environment variable.
Why Node.js Requires NODE_EXTRA_CA_CERTS for mkcert
Node.js validates TLS connections against a built-in list of root CAs bundled with the runtime. Unlike browsers or other applications, Node.js does not read certificates from the operating system's trust store (macOS Keychain, Windows Certificate Store, or Linux NSS/CA bundles).
When you run mkcert -install, the tool creates a local CA (generating rootCA.pem and rootCA-key.pem in the mkcert data directory) and attempts to install it into the system trust store via platform-specific implementations in truststore_darwin.go, truststore_windows.go, truststore_linux.go, and truststore_nss.go. However, Node.js remains unaware of these system-level changes until you explicitly provide the CA file via NODE_EXTRA_CA_CERTS.
Step-by-Step Guide to Configure NODE_EXTRA_CA_CERTS with mkcert
Install the Local CA with mkcert -install
First, initialize mkcert and install the local CA into your system trust store. This command, implemented in main.go, creates the root certificate authority files.
mkcert -install
This generates rootCA.pem (the public certificate) and rootCA-key.pem (the private key) in mkcert's data directory. You can locate this directory by running mkcert -CAROOT.
Generate Development Certificates for Your Hosts
Create a certificate for the specific hostnames or IP addresses you need for local development. The certificate generation logic resides in cert.go.
mkcert localhost 127.0.0.1 ::1
This produces files named localhost+2.pem (certificate) and localhost+2-key.pem (private key) in your current directory.
Export NODE_EXTRA_CA_CERTS Environment Variable
Set the NODE_EXTRA_CA_CERTS environment variable to the absolute path of the rootCA.pem file. This variable instructs Node.js to append the specified CA certificate to its built-in trust store.
export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"
For persistent use across terminal sessions, add this line to your shell profile (.bashrc, .zshrc, or .bash_profile).
Run Your Node.js Application
Start your Node.js server with the environment variable set. Node.js will now trust certificates signed by your mkcert CA.
node server.js
Complete Node.js HTTPS Server Example
Here is a practical implementation using the certificates generated above. This example creates a simple HTTPS server in Node.js using the mkcert-generated files.
const https = require('https');
const fs = require('fs');
const path = require('path');
// Paths to the certificate and key generated by mkcert
const certPath = path.join(__dirname, 'localhost+2.pem');
const keyPath = path.join(__dirname, 'localhost+2-key.pem');
const serverOptions = {
cert: fs.readFileSync(certPath),
key: fs.readFileSync(keyPath)
};
https.createServer(serverOptions, (req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Successfully serving HTTPS via mkcert certificates\n');
}).listen(8443, () => {
console.log('HTTPS server running at https://localhost:8443');
});
When you run this server with NODE_EXTRA_CA_CERTS set, any Node.js client connecting to https://localhost:8443 will validate the certificate successfully without throwing UNABLE_TO_VERIFY_LEAF_SIGNATURE errors.
Verifying the Certificate Trust
To confirm that Node.js recognizes the mkcert CA, you can test with a simple HTTPS request using curl or a Node.js client.
Using curl (without the -k insecure flag):
curl https://localhost:8443
If NODE_EXTRA_CA_CERTS is properly set in your environment, the connection succeeds. If you encounter curl: (60) SSL certificate problem, verify that the environment variable points to the correct rootCA.pem file located at $(mkcert -CAROOT)/rootCA.pem.
Summary
- mkcert generates a local CA and installs it into the OS trust store via
truststore_*.goimplementations, but Node.js maintains its own CA list. - Node.js requires the
NODE_EXTRA_CA_CERTSenvironment variable to trust additional CAs, as it does not read the system root store. - Set
NODE_EXTRA_CA_CERTSto$(mkcert -CAROOT)/rootCA.pemto enable trust for all Node.js processes in that environment. - Use the generated certificate files (e.g.,
localhost+2.pemandlocalhost+2-key.pem) in your Node.js HTTPS server configuration.
Frequently Asked Questions
What is the default location of mkcert's rootCA.pem?
The default location depends on your operating system. Run mkcert -CAROOT to display the exact path. On macOS and Linux, this is typically ~/Library/Application Support/mkcert or ~/.local/share/mkcert. On Windows, it resides in %LOCALAPPDATA%\mkcert. The file rootCA.pem resides in this directory alongside rootCA-key.pem.
Does NODE_EXTRA_CA_CERTS work with Node.js cluster mode?
Yes, NODE_EXTRA_CA_CERTS works with Node.js cluster mode, but you must ensure the environment variable is set in the parent process before forking workers. Child processes inherit the environment from the parent, so if the variable is exported in the main process, all cluster workers will also trust the mkcert CA. If you set the variable only in a worker after forking, it will not affect TLS validation in that worker.
Can I use NODE_EXTRA_CA_CERTS in production environments?
While technically possible, using NODE_EXTRA_CA_CERTS with mkcert in production is strongly discouraged. mkcert is explicitly designed for local development only. The root CA private key (rootCA-key.pem) is stored on your development machine, and mkcert does not implement the security controls, auditing, or certificate transparency required for production use. For production, use certificates from a publicly trusted CA (e.g., Let's Encrypt) or your organization's internal PKI infrastructure.
Why does Node.js ignore the system certificate store?
Node.js uses a statically linked OpenSSL (or BoringSSL in some builds) with a bundled CA certificate file. This design ensures consistent behavior across all platforms and prevents system-wide CA changes from unexpectedly breaking or altering Node.js TLS validation. While this improves reproducibility and security isolation, it means Node.js does not automatically trust certificates added to the macOS Keychain, Windows Certificate Store, or Linux CA bundles. The NODE_EXTRA_CA_CERTS environment variable provides the explicit mechanism to extend trust for specific use cases like local development with mkcert.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →