Create a script that reads a .env file and converts it into batched fly secrets set commands.
What Gets Created
scripts/env-to-fly-secrets.sh— The sync script (from template).env.prod— Created from.env.sampleif it exists and.env.proddoesn't (user fills in real values).gitignoreupdate — Ensures.env.prodis ignored- Justfile recipe (optional) — If a
justfileexists, adds afly-secretsrecipe
Features of the Script
- Parses
.envfiles (skips comments, blank lines, handlesexportprefix) - Validates keys match
[A-Za-z_][A-Za-z0-9_]* - Strips surrounding quotes from values
- Batches secrets into groups (default 10) to avoid Fly CLI limits
- Dry-run by default — prints commands without executing
--executeflag to actually runfly secrets set- Configurable app name (
-a) and batch size (-n)
Phase 0: Discovery
Check the target project before creating anything:
-
Existing script —
Glob("**/env-to-fly*")orGlob("**/fly-secrets*")- If found: show it and ask if user wants to replace
-
Scripts directory — Check if
scripts/exists- If not: will create it
-
.env.sample— Check if an env template exists- Could be
.env.sample,.env.example, or.env.template - If found: offer to copy it to
.env.prodas a starting point
- Could be
-
.env.prod— Check if it already exists- If found: leave it alone
-
.gitignore— Check if.env.prodis already ignoredGrep("\.env\.prod", path: ".gitignore")
-
justfile— Check if a justfile exists for adding a recipeGlob("justfile")orGlob("Justfile")
-
fly.toml— Check if Fly is configured to detect the app nameGrep("^app = ", path: "fly.toml")
Discovery Report
Present what will be created/modified and confirm.
Phase 1: Implementation
Step 1: Create Scripts Directory
mkdir -p scripts
Step 2: Create the Script
Read references/script-template.sh and write it to scripts/env-to-fly-secrets.sh.
Make it executable:
chmod +x scripts/env-to-fly-secrets.sh
Step 3: Create .env.prod (if needed)
If .env.sample (or equivalent) exists and .env.prod does not:
- Copy the sample file to
.env.prod - Tell the user to fill in production values
If no sample exists, skip this step.
Step 4: Update .gitignore
Add .env.prod to .gitignore if not already present. Place it near other .env* entries if they exist, otherwise append to the end.
Step 5: Justfile Recipe (if justfile exists)
Add a recipe like:
# Sync .env.prod to Fly secrets (dry-run by default, pass --execute to apply)
fly-secrets *args:
./scripts/env-to-fly-secrets.sh -f .env.prod {{args}}
If the app name is known from fly.toml, include -a <app-name>:
fly-secrets *args:
./scripts/env-to-fly-secrets.sh -f .env.prod -a <app-name> {{args}}
Phase 2: Verification
- Run
./scripts/env-to-fly-secrets.sh --helpto verify the script works - If
.env.prodexists with content, do a dry-run:./scripts/env-to-fly-secrets.sh -f .env.prodto show what would be set
Usage
Tell the user:
# Preview what will be set (dry-run)
./scripts/env-to-fly-secrets.sh -f .env.prod -a my-app
# Actually set the secrets
./scripts/env-to-fly-secrets.sh -f .env.prod -a my-app --execute
# Custom batch size
./scripts/env-to-fly-secrets.sh -f .env.prod -a my-app -n 5 --execute
If justfile was configured:
# Dry-run
just fly-secrets
# Execute
just fly-secrets --execute