{"id":30185840,"url":"https://github.com/brian-dlee/smuggler","last_synced_at":"2025-08-12T14:05:17.977Z","repository":{"id":50147023,"uuid":"517882229","full_name":"brian-dlee/smuggler","owner":"brian-dlee","description":"Smuggler large environment variables into your Vercel deployment","archived":false,"fork":false,"pushed_at":"2022-08-30T21:04:04.000Z","size":1040,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-22T12:12:04.829Z","etag":null,"topics":["4kb","cloudsql","encryption","prisma","ssl","vercel"],"latest_commit_sha":null,"homepage":"https://smuggler.brian-dlee.dev","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brian-dlee.png","metadata":{"files":{"readme":"README.md","changelog":"changelog/v0.2.0.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-07-26T02:10:46.000Z","updated_at":"2025-01-03T14:51:55.000Z","dependencies_parsed_at":"2022-09-26T22:00:29.520Z","dependency_job_id":null,"html_url":"https://github.com/brian-dlee/smuggler","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/brian-dlee/smuggler","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brian-dlee%2Fsmuggler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brian-dlee%2Fsmuggler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brian-dlee%2Fsmuggler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brian-dlee%2Fsmuggler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brian-dlee","download_url":"https://codeload.github.com/brian-dlee/smuggler/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brian-dlee%2Fsmuggler/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270073638,"owners_count":24522383,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-12T02:00:09.011Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["4kb","cloudsql","encryption","prisma","ssl","vercel"],"created_at":"2025-08-12T14:05:16.609Z","updated_at":"2025-08-12T14:05:17.963Z","avatar_url":"https://github.com/brian-dlee.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Smuggler\n\nSmuggle encrypted environment variables into your deployment.\n\n## Why?\n\nVercel has a 4KB restriction to the total size of all environment variables. This limitation is especially\ntroublesome if you use Firebase or Google service account authentication or if you require SSL certificates\nas part of your production application (such as with Google Cloud SQL and Prisma).\n\nhttps://vercel.com/support/articles/how-do-i-workaround-vercel-s-4-kb-environment-variables-limit\n\nThis problem and workaround are well-advertised on several issues in GitHub and a support article provided directly\nby Vercel. The recommended work around feels hacky to introduce into your code. Furthermore, depending on your\nbuild system an actual `import` might be required in order for the build process to not leave the configuration\nfiles behind when the final product is uploaded.\n\nIn an attempt to address this with my own organization and provide a stable solution for others to use, `smuggler`\nwas created.\n\nThis package may also help with the common issue of injecting GOOGLE_APPLICATION_CREDENTIALS (the path to \na Google service account credentials JSON file) or a Firebase credentials file into your application. See \nthe \"The author's use case\" below.\n\n## Live demo\n\nTake a look at the live demo at https://smuggler.brian-dlee.dev. \n\nThe code is in the [demo directory](demo).\n\n## Getting started\n\n```shell\nnpm i --save @briandlee/smuggler\n```\n\n## Config File: `.smuggler.json`\n\nThe following properties are allows in the config file. \n\n_Note: if neither `includeVariablePrefix` or `includeFiles` are supplied, there is nothing for Smuggler to do._\n\n| option                             | required | description                                               |\n|------------------------------------|----------|-----------------------------------------------------------|\n| `encryptionKeyEnvironmentVariable` | yes      | The environment variable that contains the encryption key | \n| `encryptionIVEnvironmentVariable`  | yes      | The environment variable that contains the encryption iv  |\n| `includeVariablePrefix`            | no       | A prefix used to match environment variables to smuggle   |\n| `includeFiles`                     | no       | A list of files to smuggle (as base64)                    |\n\n### `includeFiles`\n\nEntries in `includeFiles` can take on one of two forms:\n\n**type: `file`**\n\nThis is used for files that exist on disk somewhere. The file indicated by `path` will be\nread and converted to base64 before it's encrypted into the smuggler data file under the name\nindicated by `variable`. If the file does not exist or cannot be read, the operation will fail.\n\n```typescript\ninterface File {\n  type: \"file\";\n  path: string;\n  variable: string;\n}\n```\n\n**type: `variable`**\n\nThis is used for files that exist on disk somewhere, but their path is stored in an environment variable.\nThe variable indicated by `name` will be read, the file it refers to will then be read, and finally it is \nconverted to base64 and encrypted into the smuggler data file under the name\nindicated by `variable`, if supplied, or `name` otherwise. If the variable is not defined, the file does not exist, or \nthe file cannot be read the operation will fail.\n\n```typescript\ninterface Variable {\n  type: \"variable\";\n  variable?: string;\n  name: string;\n}\n```\n\n## CLI\n\n### Operation: `prepare`\n\nUse `prepare` to store environment variables and files into an encrypted file that can be uploaded as part of \nyour deployment.\n\nThis is part of step-1, in a 2 phase deployment. During part 1, expose sensitive variables to the build\nenvironment where they can be read and exported in an encrypted format before being uploaded to the build system\n(i.e. Vercel) to be packaged with the application during the application build phase.\n\n### Operation: `generate`\n\nUse `generate` to convert prepared data from phase 1 into application files that can be bundled with your application.\nWithout this step, the encoded variables do not become part of the application and will be shaken as part of builder\noptimization. If you did not prepare the data beforehand, this step can also do both the preparation and generation.\n\nIt's important to run this step as part of the normal development process. Without the generated files that result\nfrom this step, the application will not run if smuggler is invoked. Even an empty generated file will close \nthe circuit. A common remedy is to include `smuggler generate` as part of `prestart` in your package.json.\n\n### Operation: `read`\n\nUse `read` to inspect the contents of data resulting from the `prepare` step. This is only used a debugging tool.\n\n## Following the author's use case\n\n### Creating the config file\n\nIn my case, I prefix variables I want to feed into `smuggler` with `VERCEL_SECRET__`, and I store the `key` and `iv`\nparameters for encryption/decryption in the variables `VERCEL_ENCRYPTION_KEY` and `VERCEL_ENCRYPTION_IV` as recommended\nin the support article. If you are using this for Vercel you might want to follow the instructions for creating these\nvariables as outlined in the article. I've retained the encryption algorithm recommended there which requires the `key`\nand `iv` parameters to be 16 character secrets.\n\n\u003e The algorithm used in the project can be configured, but the project has not been tailored for those customizations.\n\u003e So make sure you generate your secrets accordingly.\n\n```json\n{\n  \"encryptionKeyEnvironmentVariable\": \"VERCEL_ENCRYPTION_KEY\",\n  \"encryptionIVEnvironmentVariable\": \"VERCEL_ENCRYPTION_IV\",\n  \"includeVariablePrefix\": \"VERCEL_SECRET__\",\n  \"includeFiles\": [\n    { \"type\": \"variable\", \"name\":  \"GOOGLE_APPLICATION_CREDENTIALS\", \"variable\": \"GOOGLE_SERVICE_ACCOUNT_CREDENTIALS_JSON_BASE64\" }\n  ]\n}\n```\n\n### Execute `smuggler prepare` during your CI's build phase\n\nAll necessary variables must be available during the build phase. With Vercel's CLI you can use `-b` or `--build-env`\nto create them for the build phase only.\n\nMost deployments might happen solely on Vercel's end with a Git integration, but this won't work if you have environment\nvariables exceeding 4KB because there is no where to add them unless they are in version control. If you are\nventuring down this avenue you've probably found you need to run custom CI calling Vercel's CLI when necessary.\n`prepare` should be used during this phase prior to calling Vercel's CLI to commence the build.\n\nThis step creates the encrypted data in the intermediate storage location.\n\n_Note: All variables you intend to inject into your build must be available during the `prepare` phase_\n\n```shell\nnpx -y @briandlee/smuggler prepare\n```\n\n### Add `smuggler generate` to your build phase\n\nThis step copies configuration from the intermediate storage location to the build storage location\n\nA good place for this is in `prebuild` in your `package.json`.\n\n```json\n  \"scripts\": {\n    \"prebuild\": \"smuggler generate\",\n```\n\n\u003e I also add it to `prestart` so the necessary files for startup with smuggler are always present.\n\n### Load the configuration at runtime\n\nThe data is pre-processed into source code at build time (when smuggler create is ran). Calling read will call this\ncompiled loader, decode the data and return it. In many cases, you may want to cache this result so you do not end\nup decoding data multiple times during your apps execution unless you are worried about the vulnerability of holding\nsecret data in memory or if your config data is really large.\n\nYour key and iv values must be available for read to work.\n\n```typescript\nimport { writeFileSync } from \"fs\";\nimport { read, withDefaultReadOptions } from '@briandlee/smuggler';\nimport { randomString } from \"~/utils/my-random-lib\"\n\nconst data = read(withDefaultReadOptions({\n  key: process.env.VERCEL_ENCRYPTION_KEY,\n  iv: process.env.VERCEL_ENCRYPTION_IV\n}));\n\n// Read and write my Google service account credentials\nif (data.GOOGLE_SERVICE_ACCOUNT_CREDENTIALS_JSON_BASE64) {\n  const filePath = `/tmp/${randomString(64)}.json`;\n  writeFileSync(\n    filePath,\n    Buffer.from(data.GOOGLE_SERVICE_ACCOUNT_CREDENTIALS_JSON_BASE64, 'base64')\n  );\n  process.env.GOOGLE_APPLICATION_CREDENTIALS = filePath;\n}\n```\n\n### An Example\n\nSee the [example](example/prisma-app) for an illustration for how the package is designed to be used.\n\n## Caveats\n\n - At the time of writing this, I'm using Remix (which uses esbuild). If you are using another framework that uses a \n   different build system you encounter a situation where the smuggler data is pruned from the final build (maybe in the \n   case of Next.js and their use of [nft](https://github.com/vercel/nft)).\n\n## TODO\n\n - [ ] Support additional encryption methods\n\n----\n\nMade by [me](https://brian-dlee.dev).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrian-dlee%2Fsmuggler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrian-dlee%2Fsmuggler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrian-dlee%2Fsmuggler/lists"}