Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: July 4, 2025
When building applications, we often need to use and manage configuration settings, API keys, database URLs, and other sensitive information. These are typically stored in environment files, like .env files, that an application reads at runtime. Yet, how can this same mechanism be used when we want to deploy or test an application using GitHub Actions? We need a way to create such environment files dynamically during workflow execution.
In this tutorial, we’ll explore using GitHub Actions to create an .env file in the workflow. First, we’ll cover what .env files are. After that, we’ll discuss creating a simple .env file, as well as using it at a later point within a given workflow. Subsequently, we’ll elaborate on creating multiple .env files. Lastly, we’ll consider related security practices.
Although they typically employ the .env extension and no filename, environment files are simple text files that contain key-value pairs representing configuration variables for an application:
DATABASE_URL=postgresql://localhost:5432/myapp
API_KEY=secret-api-key
NODE_ENV=production
PORT=3000
Applications read these variables at startup, enabling us to configure different settings for development, testing, and production environments without hardcoding values in the source code. These are subsequently available in the code environment.
Thus, secret or dynamic data can vary across deployments.
When code runs in GitHub Actions workflows, it doesn’t have access to the .env files on any local machine.
Because of this, we might need to recreate .env files during the workflow execution for several reasons:
In fact, without some variables, the application and, by extension, the whole workflow could fail. Therefore, it’s essential to learn how to create .env files within workflows.
Usually, the simplest way to create an environment file in GitHub Actions is to use the echo command to write content to a file.
However, for this tutorial, we create the file using GitHub Actions from GitHub. Let’s look at the YAML sample workflow env-file.yml:
name: Build and Test
on:
- push
- pull_request
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Create .env file
run: |
echo "NODE_ENV=production" >> .env
echo "PORT=3000" >> .env
echo "DATABASE_URL=postgresql://localhost:5432/testdb" >> .env
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
The above code is a GitHub Actions workflow, titled Build and Test. It triggers when developers push code or open a pull_request. It defines a single job called build, which runs on the latest Ubuntu environment. First, the workflow checks out the repository using the actions/checkout@v3 action, making the code available for the subsequent steps. Then, it creates an .env file by appending environment variables, so the application can access runtime configuration settings.
Since this is a NodeJS project, after setting up the environment file, the workflow installs the project dependencies via npm install. This ensures that all necessary packages listed in package.json are available before testing. Finally, the workflow runs the project test suite using the npm test command.
Notably, this approach works well for non-sensitive configuration values that we’re comfortable having visible in the workflow logs. However, not all data can be shared this way.
For sensitive information like API keys, passwords, or tokens, we use GitHub Secrets. GitHub Secrets are encrypted values stored securely in the repository settings that can be accessed in workflows without exposing their actual values.
To set up a GitHub secret, we follow a few steps:
Let’s see an example screen:
From the drop-down menu, we click Actions and then go to Manage environment secrets under Environment secrets:
Lastly, we add the required secret and save it. Once we set up the secrets, we can reference them in the workflow.
Let’s modify the .yml file from earlier to include those secrets:
name: Deploy Application
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Create .env file
run: |
echo "NODE_ENV=production" >> .env
echo "DATABASE_URL=${{ secrets.DATABASE_URL }}" >> .env
echo "API_KEY=${{ secrets.API_KEY }}" >> .env
echo "JWT_SECRET=${{ secrets.JWT_SECRET }}" >> .env
- name: Build application
run: npm run build
- name: Deploy to server
run: npm run deploy
The ${{ secrets.SECRET_NAME }} syntax enables us to access the stored secrets safely. GitHub automatically masks these values in workflow logs, so these won’t be visible to anyone viewing the workflow output.
Once the .env file is created, we can use it in any future steps by sourcing it:
- name: Run app with env vars
run: |
source .env
echo "Running app with API key: $API_KEY"
In most tools, just having the .env file in the root folder is enough. We don’t have to create it in other subdirectories.
In this section, we discuss advanced use cases of .env files within GitHub Actions.
Sometimes we need different environment files for different stages of the workflow.
In such instances, we can use GitHub Actions to create separate environment files:
- name: Create test environment file
run: |
echo "NODE_ENV=test" >> .env.test
echo "DATABASE_URL=${{ secrets.TEST_DATABASE_URL }}" >> .env.test
echo "API_KEY=${{ secrets.TEST_API_KEY }}" >> .env.test
- name: Create production environment file
run: |
echo "NODE_ENV=production" >> .env.production
echo "DATABASE_URL=${{ secrets.PROD_DATABASE_URL }}" >> .env.production
echo "API_KEY=${{ secrets.PROD_API_KEY }}" >> .env.production
Each step above creates a different .env file containing secrets injected from the GitHub environment, enabling different configurations for test and production stages.
This approach keeps the deployment process clean and secure across environments.
Moreover, we can create different environment configurations based on the branch or event that triggered the workflow:
- name: Create environment file
run: |
if [ "${{ github.ref }}" == "refs/heads/main" ]; then
echo "NODE_ENV=production" >> .env
echo "DATABASE_URL=${{ secrets.PROD_DATABASE_URL }}" >> .env
else
echo "NODE_ENV=development" >> .env
echo "DATABASE_URL=${{ secrets.DEV_DATABASE_URL }}" >> .env
fi
For instance, the above snippet checks the current branch name and writes the appropriate environment settings into the .env file.
This method is useful for automatically switching between production and development configurations.
In GitHub Actions workflows, maintaining clean and secure handling of secrets is essential. Real secrets should never be committed to the repository. However, we can use placeholder values in any committed .env files. In addition, secret names should be clear and descriptive. Rather than labels like SECRET1, names such as DATABASE_PASSWORD or STRIPE_API_KEY provide better clarity and organization.
Moreover, environment-specific secrets, such as those for development, staging, or production, help reduce potential impact. In the case of a compromised secret, isolation between environments limits the effect. Furthermore, periodic rotation of secrets is considered a good security measure. Especially in production environments, regular updates to keys or tokens serve as an added layer of protection.
We should avoid inserting unused variables in larger files. On the contrary, it’s a good measure to include only relevant secrets in the .env file.
Furthermore, if variables fail to load, we might also need to check where the application expects the .env file. Also, a frequent cause of missing secrets is a mismatch in secret names. Because GitHub Secrets are case-sensitive, secret names must exactly match those set in the repository settings.
Finally, sensitive values and full .env files shouldn’t be printed in production logs. Using commands to print out .env temporarily during debugging is fine for development, but we must remove any such statements once verification is complete.
In this article, we covered using GitHub Actions to create and work with an .env file in the workflow.
Creating environment files in GitHub Actions is an important skill for managing configuration and secrets in the CI/CD pipelines. By combining basic file creation techniques with GitHub Secrets, we can securely manage sensitive information while keeping the workflows flexible and maintainable.