Skip to content

Feature Request: Automatically copy default.env to .env #644

Description

@dradetsky

When using python-dotenv or similar systems, I often find myself writing instructions for other developers that look like this:

pip install -r requirements.txt
cp default.env .env
python entrypoint.py

This is because I want to exclude .env from version control, since I expect individual devs to mess with it. But I want to supply a ready-to-go env file for developers.

But I don't like this. Ideally, I don't want the developers to even have to think about .env at all if it's not relevant to them. For example, the developer might be part of our frontend team and she doesn't know/care about how we configure backend services, she just needs a copy of this running on her dev box to do her actual job. Or maybe the person who's working on this is already in the middle of learning several other things, and the last thing they need is the additional cognitive overhead of having to think about how .env works.

The above instructions are sufficiently stereotypical that they could easily be implemented into the package, provided that nobody was concerned about the additional complexity, and or considered this too out-of-scope for the package.

Here's what we do: add one additional parameter to load_dotenv and class DotEnv called init_dotenv_path which defaults to None. Now, if we attempt to load the file, if dotenv_path is not undefined, but it is a file path which does not exist, and if init_dotenv_path is defined and is a file path which does exist, then we copy init_dotenv_path to dotenv_path and try to load the file again.

Now as a user, I would just write e.g.

load_dotenv(init_dotenv_path='default.env')

And now a developer doesn't even need to know about env files to run the project.

It might also be a good idea for the logger to emit "copying default.env to .env" if this code path was used (possibly only if set to verbose).

Activity

  1. bbc2 commented on May 8, 2026

    @bbc2
    Collaborator

    I think I've seen this pattern before, and I agree about the value of simplifying the life of other developers, but I wonder if it is worth implementing inside this library.

    Have you considered this sort of code (entrypoint.py):

    import os
    import shutil
    import sys
    
    import dotenv
    
    
    def copy_no_replace(src, dst, allow_absent_src: bool = False) -> None:
        try:
            with open(src, "rb") as f_src:
                with open(dst, "xb") as f_dst:
                    shutil.copyfileobj(f_src, f_dst)
        except FileExistsError:
            pass  # Not overwriting the existing file at `dst`
        except FileNotFoundError:
            if not allow_absent_src:
                raise
    
    
    # Initialize
    copy_no_replace(src="default.env", dst=".env", allow_absent_src=True)
    dotenv.load_dotenv(dotenv_path=".env")
    print(f"Starting application (FOO: {os.environ.get('FOO')})", file=sys.stderr)
    
    # Run app code

    The above instructions are sufficiently stereotypical that they could easily be implemented into the package, provided that nobody was concerned about the additional complexity, and or considered this too out-of-scope for the package.

    That's indeed one of my concerns here. I notably fear that different app developers may have slightly different needs regarding the use of a "default .env" file.

  2. dradetsky commented on May 17, 2026

    @dradetsky
    Author

    @bbc2

    I notably fear that different app developers may have slightly different needs regarding the use of a "default .env" file.

    Are you actually aware of any of these different needs, or is this just theoretical? I'm not saying your concerns aren't reasonable, I'm just checking.

    I don't necessarily need this to be integrated into this package; As an experiment, I created python-dotenv-autocopy, so if you're really concerned about ruthlessly reducing scope, you could just close this, and I and others could just use my package. But I think it's reasonable to ask whether this functionality shouldn't just be added into this package.

    I mean, this package has an entire CLI app (I'm not even sure why), so I didn't think an extra feature to solve a common pattern was that unreasonable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions