Glenv
Sync .env files to GitLab CI/CD variables — bulk import, export, and manage environment variables via CLI
Install / Use
/learn @ohmylock/GlenvREADME
What is glenv?
glenv is a command-line tool that synchronizes .env files with GitLab CI/CD variables. It solves the problem of managing GitLab environment variables at scale — bulk import, export, diff, and sync hundreds of variables in seconds using the GitLab API.
Instead of clicking through the GitLab web UI or writing fragile bash scripts, glenv provides:
- Bulk operations — import/export entire
.envfiles with one command - Smart classification — auto-detects masked, protected, and file-type variables
- Safe workflow — preview changes with diff before applying
- Concurrent sync — parallel API calls with built-in rate limiting
- Multi-environment — manage production, staging, and custom environments from config
Why glenv over alternatives?
| Problem | glenv Solution | |---------|----------------| | GitLab UI is slow for many variables | Bulk sync hundreds of variables in seconds | | Bash scripts are fragile and sequential | Concurrent workers with retry and rate limiting | | No preview before changes | Diff command shows create/update/delete before sync | | Manual variable classification | Auto-detects masked/protected/file from key patterns | | Different configs per environment | Single YAML config for all environments |
glenv is written in Go — single static binary, no runtime dependencies, works on Linux, macOS, and Windows.
Features
- Concurrent sync — configurable worker pool with token bucket rate limiter
- Smart classification — auto-detects masked, protected, and file-type variables from key patterns
- Rate limit safe — respects GitLab API limits, handles 429 with Retry-After, exponential backoff
- Diff before sync — preview changes before applying (create/update/delete)
- Dry-run mode — see what would happen without making any API calls
- Multi-environment — sync production, staging, or any custom environment from config
- Export — download current GitLab variables to
.envfile format - .env parser — supports multiline values, quoted strings, comments, placeholder detection
- Zero config — works with just a token and project ID, config file is optional
- Self-hosted support — works with any GitLab instance, configurable rate limits
Quick Start
# Install
go install github.com/ohmylock/glenv/cmd/glenv@latest
# Set credentials (or use config file)
export GITLAB_TOKEN="glpat-xxxxxxxxxxxx"
export GITLAB_PROJECT_ID="12345678"
# Sync .env file to GitLab
glenv sync -f .env.production -e production
# Preview changes first (recommended)
glenv diff -f .env.production -e production
Installation
Homebrew (macOS/Linux)
brew install ohmylock/tools/glenv
Download binary
Download the appropriate binary for your platform from releases:
| Platform | Architecture | File |
|----------|--------------|------|
| macOS | Apple Silicon | glenv_*_darwin_arm64.tar.gz |
| macOS | Intel | glenv_*_darwin_amd64.tar.gz |
| Linux | x86_64 | glenv_*_linux_amd64.tar.gz |
| Linux | ARM64 | glenv_*_linux_arm64.tar.gz |
| Windows | x86_64 | glenv_*_windows_amd64.zip |
Go install
go install github.com/ohmylock/glenv/cmd/glenv@latest
Build from source
git clone https://github.com/ohmylock/glenv.git
cd glenv
make build
# binary: bin/glenv
Usage
Sync Variables
The primary command. Reads a .env file and syncs variables to GitLab:
# Sync single file to specific environment
glenv sync -f .env.production -e production
# Sync with dry-run (preview only)
glenv sync -f .env.staging -e staging --dry-run
# Sync all environments defined in config
glenv sync --all
# Override rate limits for self-hosted GitLab
glenv sync -f .env -e production --workers 10 --rate-limit 50
Diff (Preview Changes)
Compare local .env file with current GitLab variables:
glenv diff -f .env.production -e production
Output:
+ DB_HOST=postgres.internal
~ API_KEY: *** → ***
- OLD_VAR
= LOG_LEVEL
List Variables
# List all variables
glenv list
# Filter by environment
glenv list -e production
Export Variables
Download GitLab variables to a local .env file:
glenv export -e production -o .env.production.backup
Note: File-type variables (certificates, PEM keys) are excluded from the output and replaced with a comment
# KEY (file type, skipped). Useglenv listto see their presence.
Delete Variables
# Delete specific variable
glenv delete -e production OLD_SECRET
# Delete multiple variables
glenv delete -e staging KEY1 KEY2 KEY3 --force
Configuration
glenv works with zero config (just env vars), but a config file unlocks multi-environment workflows.
Config file locations (checked in order):
--configflag path.glenv.ymlin current directory~/.glenv.yml
# GitLab connection
gitlab:
url: https://gitlab.com # self-hosted: https://gitlab.company.com
token: ${GITLAB_TOKEN} # env var expansion supported
project_id: "12345678"
# Rate limiting (safe defaults for gitlab.com)
rate_limit:
requests_per_second: 10 # max API requests/sec (gitlab.com allows ~33)
max_concurrent: 5 # parallel workers
retry_max: 3 # retries on failure
retry_initial_backoff: 1s # backoff before first retry
# Environments
environments:
production:
file: deploy/gitlab-envs/.env.production
staging:
file: deploy/gitlab-envs/.env.staging
# Custom classification rules (extend built-in defaults)
classify:
masked_patterns: # keys containing these → masked
- "_TOKEN"
- "SECRET"
- "PASSWORD"
- "API_KEY"
- "DSN"
masked_exclude: # exceptions (NOT masked)
- "MAX_TOKENS"
- "TIMEOUT"
- "PORT"
file_patterns: # keys containing these → file type
- "PRIVATE_KEY"
- "_CERT"
- "_PEM"
file_exclude: # exceptions (NOT file type)
- "_PATH"
- "_DIR"
- "_URL"
Environment Variables
| Variable | Description |
|----------|-------------|
| GITLAB_TOKEN | GitLab Personal Access Token (scope: api) |
| GITLAB_PROJECT_ID | Project ID or URL-encoded path |
| GITLAB_URL | GitLab instance URL (default: https://gitlab.com) |
| NO_COLOR | Disable colored output when set to any non-empty value (standard convention) |
Environment variables take precedence over config file values. CLI flags take precedence over everything.
How It Works
Sync Workflow
- Parse — reads
.envfile, handles multiline values, skips placeholders - Classify — auto-detects masked/protected/file properties from key patterns and values
- Fetch — gets current variables from GitLab (paginated, concurrent-safe)
- Diff — calculates creates, updates, deletes, and unchanged
- Apply — distributes changes across worker pool with rate limiting
- Report — color-coded summary with timing and API call stats
Variable Classification
glenv auto-detects variable properties:
| Property | Condition |
|----------|-----------|
| masked | Key matches secret pattern (_TOKEN, SECRET, PASSWORD, PRIVATE_KEY, etc.) AND value is >= 8 characters AND value is single-line AND value contains only [a-zA-Z0-9_:@-.+~=/] characters |
| protected | Environment is production AND key matches secret pattern |
| file type | (Key matches file pattern (PRIVATE_KEY, _CERT, _PEM) AND value contains newlines) OR value contains PEM headers (-----BEGIN) |
Variables with placeholder values (your_, CHANGE_ME, REPLACE_WITH_) are skipped.
Variables with interpolation (${VAR}) are skipped.
Rate Limiting
glenv uses a token bucket rate limiter to stay within GitLab API limits:
| GitLab Instance | Limit | Default Config | |----------------|-------|----------------| | gitlab.com | 2,000 req/min (~33/sec) | 10 req/sec, 5 workers | | Self-hosted | Configurable | Adjust via config |
On 429 responses:
- Parse
Retry-Afterheader - Wait the specified duration
- Retry with exponential backoff + jitter
- Max 3 retries per operation
.env File Format
Supported syntax:
# Comments are skipped
KEY=value
QUOTED="value with spaces"
SINGLE_QUOTED='value'
# Multiline values
PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA...
-----END RSA PRIVATE KEY---
