Skip to content

Environments Concept

Understanding how environments work in Airbase

This explanation explores the concept of environments, why they're essential for modern development, and how Airbase implements them.


What are Environments?

Definition: Environments are isolated instances of your application running the same code but with different configurations.

Simple analogy: Like having multiple copies of your house: - Production - Your real house where you live - Staging - A test house where you try new furniture before moving it to your real house - Development - A workshop where you build furniture

Each is separate, but all based on the same blueprint.


Why Environments Matter

The Problem Without Environments

Scenario: You want to add a new feature.

Without environments: 1. Make changes 2. Deploy directly to production 3. Hope nothing breaks 4. If something breaks, users affected immediately 5. Stress! 😰

The risk: Every change is deployed directly to users.

The Solution With Environments

With environments: 1. Make changes 2. Deploy to staging 3. Test thoroughly 4. If issues found, fix and repeat 5. When ready, deploy to production 6. Confidence! 😌

The benefit: Test safely before affecting users.


Environment Types in Airbase

Default Environment (Production)

Purpose: Live application for end users

URL pattern: https://project-name.app.tc1.airbase.sg

Characteristics: - Most stable code - Thoroughly tested - Monitored closely - Changes deployed carefully

Deploy command:

airbase container deploy --yes

Prompt behavior: Defaults to "N" (safety measure)

Named Environments

Purpose: Testing, development, feature work

URL pattern: https://environment--project-name.app.tc1.airbase.sg

Examples: - staging - Pre-production testing - development - Active development - feature-auth - Feature branch testing

Deploy command:

airbase container deploy --yes staging

Prompt behavior: Defaults to "Y" (easier iteration)


How Environments Work Technically

Isolation

Each environment is completely isolated:

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│ Production   │  │ Staging      │  │ Development  │
│              │  │              │  │              │
│ Pod(s)       │  │ Pod(s)       │  │ Pod(s)       │
│ Service      │  │ Service      │  │ Service      │
│ Ingress      │  │ Ingress      │  │ Ingress      │
│              │  │              │  │              │
│ URL: prod    │  │ URL: staging │  │ URL: dev     │
│              │  │              │  │              │
│ .env vars    │  │ .env.staging │  │ .env.dev     │
└──────────────┘  └──────────────┘  └──────────────┘
     Isolated         Isolated         Isolated

What's separate: - Kubernetes pods (containers) - Kubernetes services (networking) - Ingress rules (URLs) - Environment variables - Application state

What's shared: - Container image (same code) - Base configuration (airbase.json) - Project membership

URL Routing

How Airbase generates URLs:

  1. Default environment:
  2. Pattern: {project-name}.app.tc1.airbase.sg
  3. Example: demo.app.tc1.airbase.sg

  4. Named environment:

  5. Pattern: {environment}--{project-name}.app.tc1.airbase.sg
  6. Example: staging--demo.app.tc1.airbase.sg
  7. Note the double dash (--) separator

DNS and routing:

User → DNS → ALB → Ingress Controller → Service → Pod

Each environment gets its own ingress rule pointing to its own service and pods.

Environment Variables

Per-environment configuration:

project-root/
├── .env                  # Production
├── .env.staging          # Staging
├── .env.development      # Development
└── airbase.json

Automatic selection: - Deploy to production → Reads .env - Deploy to staging → Reads .env.staging - Deploy to development → Reads .env.development

Example differences:

.env (production):

DATABASE_URL=prod-db.company.com
LOG_LEVEL=error

.env.staging:

DATABASE_URL=staging-db.company.com
LOG_LEVEL=debug

Same code, different configuration.


Common Environment Strategies

Strategy 1: Single Environment (Simple)

Environments: Production only

Use case: Simple projects, solo developers, low-risk changes

Workflow:

airbase container build
airbase container deploy --yes

Pros: - Simple - Fast - No overhead

Cons: - No testing environment - All changes go live immediately - Higher risk

Environments: Staging, Production

Use case: Most projects, teams, standard workflow

Workflow:

# Deploy to staging
airbase container build
airbase container deploy --yes staging

# Test thoroughly

# Deploy to production
airbase container deploy --yes

Pros: - Safe testing - Catches issues early - Confident deployments

Cons: - Extra step - Maintain staging environment

Strategy 3: Three-Stage Pipeline

Environments: Development, Staging, Production

Use case: Large teams, formal processes

Workflow:

# Development
airbase container build
airbase container deploy --yes development

# Staging
airbase container deploy --yes staging

# Production
airbase container deploy --yes

Pros: - Multiple testing stages - Development experimentation - Formal QA process

Cons: - More complexity - Slower iteration - More environments to maintain

Strategy 4: Feature Branches

Environments: feature-X, feature-Y, staging, production

Use case: Parallel development, multiple developers

Workflow:

# Developer A works on auth
git checkout feature/auth
airbase container build
airbase container deploy --yes feature-auth

# Developer B works on payments
git checkout feature/payments
airbase container build
airbase container deploy --yes feature-payments

# After features complete, merge and deploy to staging
git checkout main
git merge feature/auth feature/payments
airbase container build
airbase container deploy --yes staging

# Then production
airbase container deploy --yes

Pros: - Parallel development - Isolated feature testing - Review environments

Cons: - Many environments - Need cleanup - More coordination


Design Decisions

Why Environments Are Separate Deployments

Decision: Each environment is a separate Kubernetes deployment

Alternatives considered: 1. Single deployment with configuration: One app, switch config at runtime 2. Container tags: Use different container tags for environments 3. Separate deployments: What Airbase chose

Why separate deployments: - True isolation: No shared state - Independent scaling: Each environment can scale independently - Different versions: Can test old code in staging while production runs new code - Simpler rollback: Rollback one environment doesn't affect others - Clear separation: Obvious which environment you're working with

Tradeoff: Slightly more resources (each environment has its own pods)

Why the Double-Dash Separator

Decision: Use -- to separate environment and project in URLs

URL format: environment--project.app.tc1.airbase.sg

Why -- instead of . or -: - . separator: environment.project.app.tc1.airbase.sg - Problem: Looks like subdomain hierarchy - Problem: DNS complexity

  • - separator: environment-project.app.tc1.airbase.sg
  • Problem: Ambiguous (project names can have hyphens)
  • Example: staging-api-service - is this staging environment of api-service or project staging-api-service?

  • -- separator: staging--api-service.app.tc1.airbase.sg

  • Clear separation
  • Unambiguous
  • Standard pattern (used by Heroku, Netlify)

Tradeoff: Slightly unusual, but unambiguous and clear.

Why No Limits on Environment Count

Decision: No hard limit on number of environments

Rationale: - Flexibility: Teams have different needs - Feature branches: May need many temporary environments - Experimentation: Developers can try things safely

Resource management: - Soft limits via project quotas - Team responsibility to clean up - Monitoring for unused environments

Tradeoff: Potential for environment sprawl (mitigated by team practices)


Environment Lifecycle

Creation

Automatic on first deploy:

airbase container deploy --yes new-environment

What happens: 1. CLI sends deploy request 2. API checks if environment exists 3. If not, API creates Kubernetes resources 4. ArgoCD syncs new environment 5. Environment becomes accessible

No explicit "create" command needed.

Updates

Redeploy to existing environment:

airbase container build
airbase container deploy --yes staging

What happens: 1. New container image pushed 2. Kubernetes deployment updated 3. Old pods replaced with new pods 4. Rolling update (zero downtime)

Same environment, updated code.

Deletion

Explicit destruction:

airbase container destroy --yes staging

What happens: 1. CLI sends destroy request 2. API removes Kubernetes resources 3. ArgoCD syncs deletion 4. Environment becomes inaccessible 5. Resources freed

Important: Deletion is permanent.


Best Practices

Naming Conventions

Good names: - staging - Clear purpose - production - Explicit - feature-auth - Describes feature - pr-123 - Links to pull request

Bad names: - test - Too generic - alex-testing - Personal (cleanup risk) - temp - Unclear purpose - old-staging - Confusing

Convention matters for team coordination.

Environment Cleanup

Clean up after use:

# Feature merged, remove environment
airbase container destroy --yes feature-auth

# PR closed, remove environment
airbase container destroy --yes pr-123

Why cleanup matters: - Resource efficiency - Cost management - Clear environment list - Team hygiene

Tip: Set reminder to review environments monthly.

Configuration Management

Keep environment configs in sync:

Base configuration (shared):

# .env.template
PORT=3000
NODE_ENV=${ENV}

Environment-specific:

# .env.staging
DATABASE_URL=staging-db
LOG_LEVEL=debug

# .env (production)
DATABASE_URL=prod-db
LOG_LEVEL=error

Benefits: - Consistent base - Clear differences - Easy to compare


Future Enhancements

Planned Features

1. Environment metadata: - Created date - Created by - Last deployed - Description

2. Environment templates: - Predefined environment types - Standard naming - Default configurations

3. Automatic cleanup: - Delete after N days inactive - Link to git branches - Auto-delete when branch deleted

4. Environment comparison: - Diff between environments - Configuration comparison - Version tracking

5. Environment promotion:

# Promote staging to production
airbase container promote staging production


Common Questions

Can I have different code in different environments?

Yes! Each environment can run different code:

# Staging runs new code
git checkout feature-branch
airbase container build
airbase container deploy --yes staging

# Production still runs old code
# (no redeployment)

Use case: Test new features before production release.

Do environments share databases?

Not automatically. Environments are isolated.

Best practice: Use different databases per environment:

# .env.staging
DATABASE_URL=staging-database

# .env
DATABASE_URL=production-database

Why: Prevents test data from affecting production.

How much do additional environments cost?

Resource usage: Each environment uses: - 1 pod (nano: 0.25 vCPU, 512MB RAM) - Networking (ingress, service)

Actual cost: Check with your organization's Airbase administrator.

Tip: Clean up unused environments to minimize cost.

Can I deploy the same image to multiple environments?

Yes! After building once:

# Build once
airbase container build

# Deploy to multiple environments
airbase container deploy --yes development
airbase container deploy --yes staging
airbase container deploy --yes production

Benefit: Exactly the same code tested in staging and deployed to production.


Summary

Environments enable safe, confident deployments by:

  1. Isolation: Each environment is completely separate
  2. Testing: Test changes before affecting users
  3. Flexibility: Create environments as needed
  4. Configuration: Different settings per environment
  5. Experimentation: Try new things safely

The investment in using staging pays off through: - Fewer production bugs - More confident deployments - Faster iteration - Better sleep

Environments are fundamental to modern development workflows.


See Also