Skip to content

Environment Configuration

Most applications need different configuration per environment: a staging database, a production Stripe key, debug logging in dev but warn in production. This guide covers the Satusky patterns for managing that cleanly.

You have one codebase deploying to three environments. The values that differ:

  • Database connection strings
  • API keys and secrets
  • Log levels, feature flags, service URLs
  • Resource sizes (staging can be smaller than production)

Satusky gives you two tools for this: config files for structural differences (port, CPU, memory) and environment variables / secrets for runtime values.

satusky.toml is the default config 1ctl reads. You can maintain separate files for each environment:

satusky.toml ← dev defaults
satusky.staging.toml ← staging overrides
satusky.production.toml ← production spec

Create them with 1ctl init --config <name>:

Terminal window
# Create staging config
1ctl init --config staging
✅ Created satusky.staging.toml
💡 Edit satusky.staging.toml to configure resources and domain for this target.
💡 Then run: 1ctl deploy --config staging
Terminal window
# Create production config
1ctl init --config production
✅ Created satusky.production.toml
💡 Edit satusky.production.toml to configure resources and domain for this target.
💡 Then run: 1ctl deploy --config production

If a satusky.toml already exists in the same directory, init --config <name> inherits its name, port, cpu, memory, and domain fields as a starting point. Edit the generated file to set the values you want for that environment. Your satusky.production.toml might look like:

[app]
name = "my-api"
port = 8080
dockerfile = "Dockerfile"
cpu = "1"
memory = "512Mi"

And satusky.staging.toml with lighter resources:

[app]
name = "my-api"
port = 8080
dockerfile = "Dockerfile"
cpu = "0.5"
memory = "256Mi"

Commit these files. They contain no secrets — only structural config.

Pass --config <name> to target a specific config file:

Terminal window
# Deploy to staging
1ctl deploy --config staging
💡 Packaging build context...
💡 Submitting build to cloud...
Step 1/5: Building image (cloud) my-api ✓
...
✅ 🚀 Deployment for my-api is successful! Your app is live at: https://swiftbadger-f9e8d7c.satusky.com
Terminal window
# Deploy to production
1ctl deploy --config production
💡 Packaging build context...
💡 Submitting build to cloud...
Step 1/5: Building image (cloud) my-api ✓
...
✅ 🚀 Deployment for my-api is successful! Your app is live at: https://happyotter-x3k9m2.satusky.com

The --config flag accepts the environment name (staging) and resolves to satusky.staging.toml. The --config flag propagates automatically to subcommands like 1ctl env create and 1ctl logs.

Non-sensitive config: environment variables

Section titled “Non-sensitive config: environment variables”

Runtime values that aren’t secrets — log levels, service URLs, feature flags — go through 1ctl env create. They’re stored in Kubernetes ConfigMaps and visible in 1ctl env list.

Terminal window
# Set production env vars
1ctl env create \
--config production \
--env NODE_ENV=production \
--env LOG_LEVEL=warn \
--env API_BASE_URL=https://api.myapp.com

Expected output:

✅ Environment my-api created successfully
Terminal window
# Set staging env vars
1ctl env create \
--config staging \
--env NODE_ENV=staging \
--env LOG_LEVEL=debug \
--env API_BASE_URL=https://staging-api.myapp.com

Verify what’s set. env list accepts --deployment-id to scope to a specific deployment:

Terminal window
1ctl env list --deployment-id 7f1fab9e-5f87-4612-b306-3da846b95d18
NAME ENV ID DEPLOYMENT ID CREATED
my-api 798cf7bc-a85a-45b9-9a91-720e3fcade62 7f1fab9e-5f87-4612-b306-3da846b95d18 just now

To see the individual keys and values, use -o json:

Terminal window
1ctl env list -o json | jq '.[0].key_values'

Passwords, API keys, tokens — anything you wouldn’t commit to a repo — go through 1ctl secret create. Values are encrypted with AES-256-GCM before storage and are never shown after creation.

Terminal window
# Set production secrets
1ctl secret create \
--config production \
--kv DATABASE_PASSWORD=p4ssw0rd-prod \
--kv JWT_SECRET=supersecret-prod \
--kv STRIPE_SECRET_KEY=sk_live_abc123

Expected output:

✅ Secret my-api created successfully
Terminal window
# Set staging secrets
1ctl secret create \
--config staging \
--kv DATABASE_PASSWORD=p4ssw0rd-staging \
--kv JWT_SECRET=supersecret-staging \
--kv STRIPE_SECRET_KEY=sk_test_xyz789

Verify (key names only — values are never returned):

Terminal window
1ctl secret list
NAME SECRET ID DEPLOYMENT ID CREATED
my-api bcbeb9d7-958c-4aa6-b1a1-51846504cfe8 7f1fab9e-5f87-4612-b306-3da846b95d18 just now

After setting new secrets, restart pods to pick them up:

Terminal window
1ctl deploy restart --config production

In CI, skip 1ctl auth login entirely. Set SATUSKY_API_KEY as an environment variable and 1ctl uses it directly:

Terminal window
SATUSKY_API_KEY=${{ secrets.SATUSKY_TOKEN }} 1ctl deploy --config production

SATUSKY_API_KEY takes priority over any stored context file. This is safe for ephemeral CI runners because no credential file is written to disk.

A complete GitHub Actions example that deploys staging on pull requests and production on merge to main:

name: Deploy
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
deploy-staging:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install 1ctl
run: curl -fsSL https://install.satusky.com | sh
- name: Deploy to staging
env:
SATUSKY_API_KEY: ${{ secrets.SATUSKY_TOKEN }}
run: 1ctl deploy --config staging --wait
deploy-production:
if: github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install 1ctl
run: curl -fsSL https://install.satusky.com | sh
- name: Deploy to production
env:
SATUSKY_API_KEY: ${{ secrets.SATUSKY_TOKEN }}
run: 1ctl deploy --config production --wait

See CI/CD Integration for a deeper walkthrough including rollback patterns.

ItemCommit?
satusky.tomlYes
satusky.staging.tomlYes
satusky.production.tomlYes
Secret valuesNever
SATUSKY_API_KEYNever — use CI secrets

The config files contain only structural deployment spec. Secret values never touch the filesystem. Keep it that way.

  • CI/CD Integration — full GitHub Actions workflow with rollback
  • Custom Domains — attach api.myapp.com to the production deployment
  • Autoscaling — scale production based on traffic, keep staging at fixed replicas