1/velikoss/dotenv-zig v0.16

.env for Zig


dotenv zig 0.15.0

  • dotenv is a super simple single file zig library for parsing a .env file.
  • implementation is < 100 lines
  • Support for key-value pairs separated by = in the .env file.
  • trims trailing spaces in key and values
  • values in double or single quotes get stripped: "myvalue" -> myvalue
  • does not check keys for syntax correctness
  • dupes the key-values into a hashmap, so the input buffer may get deallocated without problems
  • Process environment variable support - automatically falls back to process environment when key is not found in .env file
  • Required environment variable validation - getRequired() function ensures critical variables are present
  • No dependencies

Usage

  1. with zon: zig fetch --save "thisrepo/hash" in build.zig, add the module (the name of the module is "dotenv")

  2. Create a .env file in your project or executable directory:

    # .env
    MY_ENV_VAR=hello
    ANOTHER_VAR=world
    
  3. Use dotenv to read the environment variable:

    const Env = @import("dotenv");
    pub fn main() !void {
       const alloc = std.heap.page_allocator;
       // read the env file
       var file = try std.fs.cwd().openFile(".env", .{});
       defer file.close();
       const content = try file.readToEndAlloc(alloc, 1024 * 1024);
       defer alloc.free(content);
       // parse the env file
       var env: Env = try Env.init(alloc, content);
       defer env.deinit();
       // This will first check the .env file, then fall back to process environment if not found
       std.debug.print("{s}\n", .{env.get("password").?});
       // Use the environment variables
       // ...
    }
    

    Alternatively, use initWithPath for a more convenient approach:

    const Env = @import("dotenv");
    pub fn main() !void {
       const alloc = std.heap.page_allocator;
       // initWithPath handles file opening, reading, and cleanup automatically
       // Set use_process_env=true to fall back to process environment if .env file is not found
       var env: Env = try Env.initWithPath(alloc, ".env", 1024 * 1024, true);
       defer env.deinit();
       // This will first check the .env file, then fall back to process environment if not found
       std.debug.print("{s}\n", .{env.get("password").?});
       // Use the environment variables
       // ...
    }
    
  4. Use dotenv to get a key from a dotenv file at comptime:

    const Env = @import("dotenv");
    pub fn main() !void {
       const content = @embedFile(".env");
       try expect(try Env.parse_key("no key", content) == null);
       const password = try Env.parse_key("password", content);
       try expect(std.mem.eql(u8, password.?, "mysecretpassword"));
    }
    
  5. Process environment variable support (for cloud deployments):

    When a key is not found in the .env file, Env.get() automatically falls back to reading from the process environment. This makes it perfect for cloud deployments where environment variables are provided by the platform.

    Option A: Initialize without a .env file (process environment only):

    const Env = @import("dotenv");
    pub fn main() !void {
       const alloc = std.heap.page_allocator;
       // Initialize without a .env file - will use process environment only
       var env: Env = try Env.init(alloc, null);
       defer env.deinit();
    
       // This will read from process environment (e.g., set by Docker, Heroku, AWS Lambda, etc.)
       if (env.get("DATABASE_URL")) |url| {
          std.debug.print("Database URL: {s}\n", .{url});
       }
    }
    

    Option B: Use initWithPath with fallback (recommended for cloud deployments):

    const Env = @import("dotenv");
    pub fn main() !void {
       const alloc = std.heap.page_allocator;
       // If .env file exists, use it; otherwise fall back to process environment
       // This works seamlessly in both local development and cloud deployments
       var env: Env = try Env.initWithPath(alloc, ".env", 1024 * 1024, true);
       defer env.deinit();
    
       // This will check .env file first, then process environment
       if (env.get("DATABASE_URL")) |url| {
          std.debug.print("Database URL: {s}\n", .{url});
       }
    }
    

    This is particularly useful for:

    • Cloud platforms (Heroku, AWS Lambda, Google Cloud Run, etc.)
    • Docker containers with environment variables
    • CI/CD pipelines
    • Production environments where .env files should not be included
    • Local development where you want .env file support with cloud deployment compatibility
  6. Required environment variables with getRequired():

    For cases where an environment variable is mandatory, use getRequired() which returns an error if the variable is missing:

    const Env = @import("dotenv");
    pub fn main() !void {
       const alloc = std.heap.page_allocator;
       var env: Env = try Env.initWithPath(alloc, ".env", 1024 * 1024, true);
       defer env.deinit();
    
       // getRequired() returns error.MissingRequiredEnvVar if the key is not found
       const database_url = try env.getRequired("DATABASE_URL");
       const api_key = try env.getRequired("API_KEY");
    
       std.debug.print("Database URL: {s}\n", .{database_url});
       std.debug.print("API Key: {s}\n", .{api_key});
    }
    

    This is useful for:

    • Ensuring critical configuration is present before application startup
    • Providing clear error messages when required variables are missing
    • Avoiding null checks when you know a variable must exist

Docker Testing

The repository includes Docker support for testing process environment functionality:

docker-compose up --build

This will run all tests with environment variables set via Docker Compose, verifying that process environment variable support works correctly.

Contributing

Contributions are welcome! Fork the repository and submit a pull request.

License

dotenv-zig is licensed under the MIT License. See LICENSE for details.

Package Contents

  • licenses.txt
  • zigmod.lock
  • LICENSE
  • .dockerignore
  • build.zig
  • zigmod.yml
  • src/root.zig
  • Dockerfile
  • README.md
  • build.zig.zon
  • docker-compose.yml
  • .gitignore

History

Published On Tree @ Commit Size
v0.16 Wed, 26 Nov 2025 09:13:38 UTC Tree 19.586 KB
v0.15 Mon, 17 Nov 2025 19:01:32 UTC Tree 7.747 KB
v0.14 Thu, 24 Apr 2025 21:04:26 UTC Tree 7.741 KB
v0.13 Tue, 08 Apr 2025 15:48:05 UTC Tree 6.544 KB
v0.12 Wed, 12 Jun 2024 15:34:02 UTC Tree 10.964 KB
v0.11 Wed, 12 Jun 2024 15:25:43 UTC Tree 10.912 KB
v0.10 Wed, 12 Jun 2024 15:22:48 UTC Tree 10.857 KB
v0.9 Wed, 12 Jun 2024 15:21:54 UTC Tree 10.875 KB
v0.8 Wed, 12 Jun 2024 14:37:08 UTC Tree 10.860 KB
v0.7 Wed, 12 Jun 2024 14:35:42 UTC Tree 10.813 KB
v0.6 Wed, 12 Jun 2024 14:33:30 UTC Tree 12.354 KB
v0.5 Wed, 12 Jun 2024 14:27:44 UTC Tree 12.329 KB
v0.4 Wed, 12 Jun 2024 14:27:32 UTC Tree 12.333 KB
v0.3 Wed, 12 Jun 2024 14:26:47 UTC Tree 12.337 KB
v0.2 Wed, 12 Jun 2024 09:33:53 UTC Tree 12.254 KB
v0.1 Wed, 12 Jun 2024 09:18:57 UTC Tree 12.152 KB