How do I work around Vercel's 4KB Environment Variables limit?

Environment Variables are key-value pairs configured outside of your source code and can differ based on the environment they are used in. There is a maximum size of 4KB allowed for Environment Variables per Deployment. In this article, a method will be presented that will allow the use of Environment Variables that exceed the limit of 4KB.

Workaround Overview

If this limit is reached, the workaround is to encrypt the required key-value pairs as a single encrypted value of smaller size using an encryption tool like AES Encryption and a pair of secrets that will be stored on Vercel as Environment Variables.

The file containing the encrypted content will then be added to the Deployment and the original key-value pairs can be decrypted by using the equivalent decryption tool such as AES Decryption with the encryption secrets stored on Vercel as Environment Variables.

Note:

To explore the code directly, visit the GitHub repository.

Step 1: Store the Secrets

Create two 16 character secrets (referred to as IV and secret key) using a random string generator such as Randorm.org and store them as Environment Variables in your Vercel Dashboard like so:

SERVICE_ENCRYPTION_IV="uf0k0dx55rp7u1sg"
SERVICE_ENCRYPTION_KEY="jc7xh9d2lvw2uluo"

The IV and Secret Key for Encryption.

Pull these variables locally by using the Vercel CLI like so:

vercel env pull

Pulling environment variables locally (they will be stored in the .env file) with Vercel CLI.

Step 2: Create the Encrypted Content

Then, create the content of the key-value pairs for your service such as the following:

{
    "type": "service_account",
    "project_id": "pid",
    "private_key_id": "privateid",
    "private_key": "privatekey",
    "client_email": "myemail@email.com",
    "client_id": "clientid",
    "auth_uri": "https://accounts.google.com/o/oauth2/auth",
    "token_uri": "https://accounts.google.com/o/oauth2/token",
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs"
}

Key-value pairs for a service that would have normally been stored as separate environment variables.

Copy all the content and paste it in the encryption text box of an encryption tool like AES Encryption available online. Select the mode as CBC, the key size in bits as 128, the IV and Secret key as previously saved, Base64 as the output text format and click Encrypt. Copy the AES Encrypted output and save it in a file such as service-account.enc.js as a Javascript variable like so:

module.exports = { encrypted: 'eHo92pMoabgScx9K1XtTnrUpIAyDtykiFCRhR3tRpG...' };

Storing encrypted content as a Javascript variable in a file.

Step 3: Create an API Endpoint for Decryption

Now that the encrypted content is in place, create the function that will decrypt the content based on the IV, secret key, and passed encrypted content. For example, in a Next.JS project, create a file called decrypt.js in the pages/api folder and use the following code (Make sure you add and the crypto dependency):

import crypto from 'crypto';

export default (req, res) => {
  const algorithm = 'aes-128-cbc';
  const decipher = crypto.createDecipheriv(
    algorithm,
    process.env.SERVICE_ENCRYPTION_KEY,
    process.env.SERVICE_ENCRYPTION_IV
  );
  let decrypted = decipher.update(req.body.data, 'base64', 'utf8');
  decrypted += decipher.final('utf8');
  res.status(200).json(JSON.parse(decrypted))
}

An API Route that takes decrypts content in the request body and using the IV and secret key from environment variables.

Step 4: Use the API Route to Decrypt the Encrypted Content

Use the API Route in your front-end code to decrypt the encrypted content stored in service-account.enc.js with the following code:

import service from "../service-account.enc";
import useSWR from 'swr'
import axios from 'axios';

const fetchWithData = (url, encrypt) => axios.post(url, { data: encrypt }).then(res => res.data);

export default function Home() {
  const { data, error } = useSWR(['/api/decrypt', service.encrypted], fetchWithData);
  if (error) return <div>failed to load</div>
  if (!data) return <div>loading...</div>
  return (
    <div>
      <h2>Saving large environment variables</h2>
      <h3>Auth-uri: {data.auth_uri}</h3>
    </div>
  )
}

The frontend code required to decrypt the encrypted service account content using the API Route with SWR and Axios.

If more services are added, encrypt each json data for a service using AES Encryption, store it in a separate variable and use the same API Route to decrypt each one.

The full code is available here.

Updated September 16th 2021