Show HN: Envelope – A modern environment variable cli tool

github.com

103 points by mattrighetti 6 days ago

Hey HN! I've built this cli tool to manage env variables of a project, but mostly for fun and to try out Rust and the clap crate.

I had this idea when I made a big mistake and broke some production stuff because I had a very messy .env file laying around in my project.

I was implementing new features for one of my projects and in my .env file I had the test database url commented out and the production one was not. Long story short, I applied migrations to the production database instead of my local test one and broke a lot of production APIs :')

I wanted a tool that could easily help me spot these issues before something bad happened, and so I built envelope for that reason.

Instead of a \.env(\..+)? file, I now use this tool to add variables to different configurations: dev, prod etc. and I feed them to the program I am executing on a one liner.

  $ envelope init
  $ envelope add dev db_url localhost:5432/postgres
  $ envelope add dev db_username username
  $ envelope add dev db_pwd pwd
  $ export $(envelope list dev)
  $ ./run.sh
This way I am explicitly exporting the dev environment without relying on the fact that everything is in order in my .env file (another approach would be to have a .env.dev file)

A very useful feature that I use quite a lot is the `check` command which is going to tell you which environment you have currently active

  $ export $(envelope list dev)
  $ envelope check
  > dev
I don't think this tool is going to be useful to anybody, but I wanted to share this with you in case there is someone that can make good use of it or find particular scenarios where this could be used instead of .env files, either way I had a lot of fun building it
leetrout 6 days ago

A word of caution - this is a way to leak your secrets through your shell history:

  $ envelope add dev db_pwd pwd
There are settings such that a command that starts with a space will not be saved in the history which would help here but I would be very careful about how you use this.
  • bomewish 4 days ago

    What’s the threat model? If an attacker has access to your shell history then don’t they then already have access to basically everything else?

    • leetrout 4 days ago

      No, not necessarily. Compared to interactive prompts / processes, at a minimum ones that can help audit access (e.g. 1password), there is an immediate layer of defense missing when things are just sitting in plain text in the history. (Same extends to our beloved `.env` files.)

      If you do a lot of remote pairing or screen sharing then you also remove the risk of sharing on accident by searching or walking up through your command history.

  • mattrighetti 6 days ago

    Mine was a bad example :) the command also lets you input stuff from stdin for that very case

bloopernova 6 days ago

Interesting!

Have you looked at mise-en-place at all? It's written in rust too, and might have some cool ideas to use: https://mise.jdx.dev/

breck 6 days ago

I like it.

Env variables should be a solved problem but no one has made the simplest general solution yet. Seems like you are on track.

One suggestion: no need to use SQLite. Just develop a simple (and _lasting_), plain text DSL and save to a file.

Here's one I made using your example.

https://sdk.scroll.pub/designer/#parsers%0A%20valueCell%0A%2...

I'm happy to chat more to nail that design if that would be helpful.

  • cbarrick 6 days ago

    Seems like .env is already an ideal DSL here. It's just a subset of shell. Easy to parse and index too.

    • breck 5 days ago

      It's close to ideal, but not ideal.

  • eikenberry 6 days ago

    > Env variables should be a solved problem

    I think the main problem is that this problem is 99% solved by the shell alone. Shells are very versatile and it is quite easy to setup different environments using your shell. I'd bet that the crossover of people good at manipulating environments on workstations and people good with shells is pretty big. That is, the people with good domain knowledge have little motivation to write tools to address this.

  • bloopernova 6 days ago

    A parser playground? Wow that is very cool.

    • breck 5 days ago

      Thanks. It is not "great" yet but it is pretty good and reliable and has served me well for many years.

      At some point I may clean up the code so that it can really shine.

      Higher priority though is getting support for this Parsers language in Sublime and VS Code.

  • gtirloni 6 days ago

    I was thinking the same because how do you version control SQLite in git?

    • skeledrew 6 days ago

      I don't think you want your secrets committed...

      • gtirloni 5 days ago

        It's common for projects to have placeholder values for dev/local environments.

        Environment variables aren't only for secrets (some say they should have never been).

        • skeledrew 5 days ago

          Sure, but we've seen time and again where someone got hacked because secrets got committed, whether accidentally or deliberately. Why tempt fate with something that encourages committing of any env vars?

          The reason why we even pull these things out in the first place is because they're considered dynamic values. Otherwise we'd just hardcode them in a committed constants file.

          • gtirloni 5 days ago

            This is a tool to manage environment variables. People use .env files with dev/local env var values in Git repositories for a good reason. They won't stop doing this.

tomwphillips 6 days ago

Of all the adjectives to use, why “modern”?

Very common these days. I don’t get it.

  • peter_l_downs 6 days ago

    I think a lot of new entrants to previously-well-explored spaces tend to label themselves as "modern" in order to signify that there is something new about their approach.

    For instance, I have a migrations library that I descibre as "modern" because it is designed for a continuous deployment environment where you're automatically running migrations on container startup — there are tons of existing popular migrations libraries, but none of them work this way because they were written in the era that you'd manually run sql commands in prod. I say "modern" so that if anyone finds my library, they realize that it was created recently based on more recent dev/ops trends.

    Maybe I should drop the "modern"? I do see a lot of people describe their code as "minimal" or "clean", which is pretty meaningless to me, so I get that "modern" could come across that way as well.

    • tomwphillips 5 days ago

      Interesting. My take is more negative than that: modern indicates they are unaware of prior art and the key challenges in the particular space, and consequently the software is buggy and/or fundamentally broken its approach.

      I think you should drop “modern” for something like “designed for CI”, “CI-first” or “CI-native”. It’s more informative.

    • skeledrew 6 days ago

      Another issue with using such relative qualifiers IMO is that they become meaningless over time, as the namespace becomes polluted as every few years something addressing some problem with a potentially different approach is given a similar qualifier.

    • Aeolun 4 days ago

      Maybe? I think, everything else being equal, that “modern” is still a relatively positive signal to me.

  • bityard 6 days ago

    I've noticed it's something a lot of Rust programs describe themselves as. Implying that software written in other programming languages is somehow vintage or obsolete, I guess.

    • whateveracct 5 days ago

      Rust has a very pronounced hype/ marketing/PR culture.

  • rpigab 6 days ago

    Ripgrep is recent and written in Rust, but it does not describe itself as modern, even if some apects of it are.

    Its interface is designed to be an almost drop-in replacement of grep, which makes it "old style".

    I think software can be old style, modern, or neutral. Most software written today aims for modern, it seems logical.

    • Aeolun 4 days ago

      Ripgrep is definitely much more usable than legacy grep though.

  • keb_ 6 days ago

    Same, except I take issue with the word "tool." Like a program? A library? A screwdriver? Very ambiguous. Very common these days as well. I don't get it.

    • looperhacks 6 days ago

      It's explicitly called a "cli tool", not very ambiguous imo

      • keb_ 5 days ago

        Not quite. Could be Call Level Interface, Command Line Interface, Common Language Infrastructure, or Clintonville Municipal Airport which has the airport code of "CLI".

        • superb_dev 5 days ago

          At this point you’re being intentionally obtuse. “CLI tool” is pretty non-ambiguous given the context

  • RadiozRadioz 6 days ago

    Maybe it's a synonym for "Rust/Go instead of C/C++"

  • oopsallmagic 6 days ago

    [flagged]

    • mattrighetti 6 days ago

      Quite the contrary, I think that env variables have been in this state for this long because they just works and I'm all in with the say "don't reinvent the wheel". I just used modern because it's a tool made in 2023-2024 with Rust, but yeah others may be right that it's just meaningless. I'll probably remove it.

Kwpolska 6 days ago

The docs don’t make it very obvious how are the environment variables actually applied. And I think .env files are much easier to manage and share. `envelope check` could be replaced with a CURRENT_ENV environment variable in an .env file. I can’t see how it would help avoid environment confusion more than $CURRENT_ENV displayed in your prompt would. (Or even better, not having production credentials on developers’ machines…)

  • mattrighetti 6 days ago

    > The docs don’t make it very obvious how are the environment variables actually applied.

    Actually, they are not applied. This is a tool that helps you manage them, you can see it as a replacement of .env files.

    > `envelope check` could be replaced with a CURRENT_ENV environment variable in an .env file

    Can you elaborate more on this? I've never used that tbh and I'm interested

    • Kwpolska 5 days ago

      > Actually, they are not applied. This is a tool that helps you manage them, you can see it as a replacement of .env files.

      The point of .env files is for tools (shells or libraries like dotenv) to read the file and actually use them. How do you do that with your tool, considering it uses a custom format?

      > Can you elaborate more on this? I've never used that tbh and I'm interested

      There is nothing special, just define a variable in .env, and then either echo it manually, or change your shell prompt to apply it.

globular-toast 5 days ago

Seems neat, but direnv can do more despite this claiming to be "modern".

another-dave 6 days ago

> This way I am explicitly exporting the dev environment without relying on the fact that everything is in order in my .env file (another approach would be to have a .env.dev file)

What did you find lacking with the .env.dev approach? (Or if some tool doesn't support .env.dev could always symlink .env → .env.dev)

  • mattrighetti 6 days ago

    The cons of that is that sometime I'd end up with 3 different files for different scenarios and in one particular case my tool only cared about the .env file, so I had to do a lot of `mv .env.dev .env` every time I had to switch to another env configuration.

    • another-dave 5 days ago

      But running:

          ln -sf .env.dev .env
      
      doesn't seem any worse than running:

          envelope export dev
      
      ?
      • Aeolun 4 days ago

        Well… one is just a tad more readable.

        • another-dave 4 days ago

          My personal approach is to favour more universal tools, so would prefer using symlinks & then adding a shell alias (or a package.json script) if I want to make it quicker to type.

          To each their own, though!

stephenr 6 days ago

> I had the test database url commented out and the production one was not.

I feel like this is a giant red flag. Why on earth is your production database accessible from anywhere (ie your PC) without some kind of extra layer of security like a VPN or SSH tunnel?

  • mattrighetti 6 days ago

    The production database that I'm talking about is a Postgres instance that is only available to me in my house for my side projects, it contains random stuff that can be queried through APIs that me and my family use with an app that works only when we are connected to our home LAN. Therefore I'm not paying as much attention when I do stuff with it as I would on a database that thousands of users rely on. Still, it sucks because it took quite some time to bring it back to a working state. Lesson learned

skeledrew 6 days ago

Hmm I fairly recently started saving variables which tend to be shared among multiple projects in a central location, grouped in sh files and sourcing as needed. This gives me an idea to improve that flow...

applgo443 5 days ago

When i deploy a webapp on azure, it expects me to put env variables in a file or their own tool (key value fields) where you can add env variables one by one.

Is there a way to use envelope in places like those?

SeriousM 6 days ago

envkey.com is also distributing environment variables

nodesocket 4 days ago

Any plans to support encryption at rest?

cranberryturkey 6 days ago

how do I install the damn thing??

  • mattrighetti 6 days ago

    I'll copy the answer to a similar question in the issues:

    > I used to have a `brew tap` for it but I've removed it temporarily. To install it you can download the binary file in the latest release[0] and move it to your `/usr/local/bin` folder (on macOS this is what I'd do) or any other folder that is in your `$PATH`.

    [0]: https://github.com/mattrighetti/envelope/releases/latest

twerkmonsta 6 days ago

you probably don’t need sql

  • mattrighetti 6 days ago

    Agreed, sqlite is definitely overkill for this kind of task but it's also lightweight and fast, so why not?