Preview Environments for Every Feature — Atmosly Guide

Preview environments (feature environments) provide isolated testing for every PR. Learn how Atmosly automates ephemeral Kubernetes environments with database snapshots and cost optimization.

Preview Environments for Every Feature

Waiting until staging to test features slows development and increases bugs. Preview environments—also called feature environments or ephemeral environments—solve this by automatically creating isolated, production-like environments for every pull request or feature branch. Developers and product teams can test changes in a real environment before merging, catching issues early and accelerating feedback loops.

This guide explains preview environments, their benefits, and how Atmosly makes feature environment provisioning instant and cost-effective through Kubernetes-native automation.

What are Preview Environments?

Preview environments are temporary, isolated environments that mirror production, created automatically for each feature branch or pull request. They allow developers, QA, and stakeholders to interact with changes before they're merged.

Key Characteristics

  • Automatic creation: Triggered by Git events (PR opened, branch pushed)
  • Isolated: Each environment is independent (separate database, services)
  • Production-like: Same tech stack, similar data
  • Ephemeral: Automatically deleted when PR closes or merges
  • Unique URL: Each environment has its own domain (e.g., pr-123.preview.atmosly.io)

Preview Environments vs Traditional Staging

AspectShared StagingPreview Environments
ParallelizationOne staging → bottleneckUnlimited parallel testing
IsolationShared state → conflictsFully isolated per PR
Test confidenceLow (others' changes interfere)High (only your changes)
CleanupManual or neverAutomatic on PR close
DatabaseShared (risky)Isolated snapshot
Setup timeManual coordinationAutomatic (2-5 minutes)

Why Preview Environments Matter

1. Faster Feedback Loops

Test features immediately after pushing code, not after merging to main:

  • Developers: Validate changes in realistic environment
  • Designers: Review UI/UX without local setup
  • Product managers: Test new features before release
  • QA: Run tests in parallel across multiple PRs

2. Catch Integration Issues Early

Local development doesn't catch everything:

  • Environment-specific bugs (networking, DNS, load balancing)
  • Database migration issues
  • Third-party API integration problems
  • Performance issues under realistic load

3. Enable Stakeholder Reviews

Non-technical stakeholders can review features via URL:

# Example: PR comment with preview URL
🚀 Preview environment ready!

URL: https://pr-456.preview.atmosly.io
Branch: feature/user-authentication
Deploy time: 2m 34s

What's new:
- OAuth2 login flow
- User profile page
- Password reset

@product-team @designers ready for review!

4. Parallel Development

Multiple teams work independently without stepping on each other:

  • Team A tests payment flow in pr-100.preview.atmosly.io
  • Team B tests search feature in pr-101.preview.atmosly.io
  • No conflicts, no waiting for staging availability

Atmosly's Feature Environment Architecture

Atmosly makes preview environments practical by leveraging Kubernetes namespaces, GitOps automation, and cost optimization.

How Atmosly Creates Feature Environments

┌─────────────────────────────────────────────┐
│  Developer pushes to feature branch         │
└──────────────┬──────────────────────────────┘
               │
               ▼
┌─────────────────────────────────────────────┐
│  GitHub/GitLab webhook → Atmosly            │
└──────────────┬──────────────────────────────┘
               │
               ▼
┌─────────────────────────────────────────────┐
│  Atmosly provisions (2-5 minutes):          │
│  1. Kubernetes namespace (isolated)         │
│  2. Database snapshot (anonymized)          │
│  3. Application deployment                  │
│  4. Ingress with unique subdomain           │
│  5. Monitoring & logging                    │
└──────────────┬──────────────────────────────┘
               │
               ▼
┌─────────────────────────────────────────────┐
│  Preview URL posted to PR:                  │
│  https://pr-456.preview.atmosly.io          │
└─────────────────────────────────────────────┘

Step-by-Step: Atmosly Feature Environment Flow

Step 1: Enable Feature Environments for Repository

# atmosly.yaml (in repository root)
apiVersion: atmosly.io/v1
kind: PreviewEnvironment
metadata:
  name: payment-service
spec:
  trigger:
    branches:
      include:
        - feature/*
        - fix/*
      exclude:
        - main
        - release/*
  lifetime: 7d  # Auto-delete after 7 days
  resources:
    application:
      image: ${CI_REGISTRY}/${CI_PROJECT_PATH}:${CI_COMMIT_SHA}
      replicas: 1
      resources:
        cpu: 250m
        memory: 256Mi
    database:
      type: postgresql
      version: "15"
      snapshot: production  # Clone from prod (anonymized)
      size: db.t3.micro
    cache:
      type: redis
      version: "7"
  ingress:
    domain: ${PR_NUMBER}.preview.atmosly.io
    tls: true
  notifications:
    slack:
      channel: "#dev-payments"
      events: [created, ready, deleted]

Step 2: Developer Creates Pull Request

# Developer workflow
git checkout -b feature/oauth-login
# ... make changes ...
git commit -m "Add OAuth2 login flow"
git push origin feature/oauth-login
# Create PR on GitHub/GitLab

Step 3: Atmosly Automatically Provisions

Within 2-5 minutes, Atmosly creates:

# Kubernetes namespace
apiVersion: v1
kind: Namespace
metadata:
  name: preview-pr-456
  labels:
    atmosly.io/preview: "true"
    atmosly.io/pr: "456"
    atmosly.io/branch: "feature-oauth-login"
    atmosly.io/owner: "alice"

---
# Application deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: payment-service
  namespace: preview-pr-456
spec:
  replicas: 1
  template:
    spec:
      containers:
      - name: app
        image: myregistry.io/payment-service:sha-abc123
        resources:
          requests:
            cpu: 250m
            memory: 256Mi
        env:
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: db-credentials
              key: url
        - name: REDIS_URL
          value: redis://redis:6379

---
# Ingress with unique URL
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: payment-service
  namespace: preview-pr-456
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - pr-456.preview.atmosly.io
    secretName: wildcard-cert
  rules:
  - host: pr-456.preview.atmosly.io
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: payment-service
            port:
              number: 80

Step 4: Atmosly Posts Comment to PR

# GitHub PR comment (automated)
## 🚀 Preview Environment Ready

✅ **Status:** Deployed successfully  
🌐 **URL:** https://pr-456.preview.atmosly.io  
🏷️ **Version:** sha-abc123  
⏱️ **Deploy time:** 2m 34s  
💾 **Database:** PostgreSQL 15 (snapshot from production, anonymized)  
🗑️ **Auto-delete:** 7 days or on PR close  

### What's deployed:
- Payment service (feature/oauth-login)
- PostgreSQL database (isolated)
- Redis cache

### Quick links:
- 📊 [Monitoring Dashboard](https://atmosly.io/preview/pr-456/metrics)
- 📝 [Logs](https://atmosly.io/preview/pr-456/logs)
- 🔍 [Traces](https://atmosly.io/preview/pr-456/traces)

**Test credentials:**
- Email: [email protected]
- Password: test123

Database Handling: The Biggest Challenge

Preview environments are easy for stateless apps but tricky for databases. Atmosly provides multiple strategies:

Option 1: Database Snapshots (Recommended)

Clone production database with anonymization:

# Atmosly config
database:
  source: production
  snapshot:
    enabled: true
    anonymize:
      - table: users
        columns:
          email: faker.email
          phone: faker.phoneNumber
          ssn: "XXX-XX-XXXX"
      - table: payments
        columns:
          cardNumber: "**** **** **** ****"
          cvv: "***"
  size: db.t3.micro  # Smaller instance for cost

Option 2: Seeded Test Data

Start with empty database + seed script:

 

Option 3: Shared Staging Database

Use shared database with unique schema per preview:

 

Cost Optimization for Preview Environments

Preview environments can get expensive. Atmosly includes cost controls:

1. Right-Sizing

# Preview envs use smaller resources than production
resources:
  application:
    cpu: 250m      # vs 1000m in prod
    memory: 256Mi  # vs 2Gi in prod
  database:
    size: db.t3.micro  # vs db.r6g.xlarge in prod

2. Auto-Deletion Policies

# Auto-cleanup rules
lifecycle:
  deleteAfter: 7d          # Max lifetime
  deleteOnMerge: true      # Clean up when PR merges
  deleteOnClose: true      # Clean up when PR closes
  deleteIfIdle: 24h        # Delete if no traffic for 24h
  pauseAfterHours: 2h      # Pause (scale to 0) after 2h inactivity

3. Scheduled Shutdowns

# Shut down nights/weekends
schedule:
  weekdays:
    start: "09:00"  # Scale up at 9 AM
    stop: "18:00"   # Scale to 0 at 6 PM
  weekends: false      # Don't run on weekends

4. Spot Instances for Databases

# Use spot instances where possible
database:
  spotInstances: true  # 70% cost savings
  fallback: on-demand  # Fall back if spot unavailable

Multi-Service Applications

For microservices, preview environments can deploy entire stacks:

# atmosly.yaml for microservices app
apiVersion: atmosly.io/v1
kind: PreviewEnvironment
spec:
  services:
    - name: frontend
      image: frontend:${CI_COMMIT_SHA}
      port: 3000
      ingress:
        domain: ${PR_NUMBER}.preview.atmosly.io
    
    - name: api-gateway
      image: api-gateway:${CI_COMMIT_SHA}
      port: 8080
    
    - name: payment-service
      image: payment-service:${CI_COMMIT_SHA}
      port: 8081
    
    - name: order-service
      image: order-service:${CI_COMMIT_SHA}
      port: 8082
  
  databases:
    - name: users-db
      type: postgresql
      snapshot: production
    - name: orders-db
      type: mongodb
      snapshot: production
  
  external:
    # Use shared staging services for cost savings
    - name: elasticsearch
      url: https://staging-es.example.com
    - name: kafka
      brokers: staging-kafka:9092

CI/CD Integration

GitHub Actions Example

# .github/workflows/preview.yml
name: Deploy Preview Environment

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  deploy-preview:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Build Docker image
        run: |
          docker build -t myregistry.io/app:${{ github.sha }} .
          docker push myregistry.io/app:${{ github.sha }}
      
      - name: Deploy to Atmosly
        uses: atmosly/deploy-action@v1
        with:
          api-key: ${{ secrets.ATMOSLY_API_KEY }}
          pr-number: ${{ github.event.pull_request.number }}
          image: myregistry.io/app:${{ github.sha }}
      
      - name: Comment on PR
        uses: atmosly/comment-action@v1
        with:
          pr-number: ${{ github.event.pull_request.number }}
          message: |
            🚀 Preview ready: https://pr-${{ github.event.pull_request.number }}.preview.atmosly.io

GitLab CI Example

# .gitlab-ci.yml
deploy-preview:
  stage: preview
  image: atmosly/cli:latest
  script:
    - atmosly preview deploy \
        --pr $CI_MERGE_REQUEST_IID \
        --image $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA \
        --wait
    - echo "Preview URL: https://pr-$CI_MERGE_REQUEST_IID.preview.atmosly.io"
  environment:
    name: preview/mr-$CI_MERGE_REQUEST_IID
    url: https://pr-$CI_MERGE_REQUEST_IID.preview.atmosly.io
    on_stop: cleanup-preview
  only:
    - merge_requests

cleanup-preview:
  stage: cleanup
  script:
    - atmosly preview delete --pr $CI_MERGE_REQUEST_IID
  when: manual
  environment:
    name: preview/mr-$CI_MERGE_REQUEST_IID
    action: stop

Testing in Preview Environments

Automated Testing

# Run E2E tests against preview environment
npm run test:e2e -- --base-url=https://pr-456.preview.atmosly.io

# Run load tests
k6 run load-test.js --env BASE_URL=https://pr-456.preview.atmosly.io

# Run security scans
zap-baseline.py -t https://pr-456.preview.atmosly.io

Visual Regression Testing

# Percy, Chromatic, or custom
const puppeteer = require('puppeteer');

const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://pr-456.preview.atmosly.io');
await page.screenshot({ path: 'preview.png', fullPage: true });

// Compare with baseline

Security Considerations

Authentication

# Protect preview environments
security:
  authentication:
    type: basic-auth
    username: preview
    password: ${RANDOM_PASSWORD}  # Posted to PR
  
  # Or use OAuth
  authentication:
    type: oauth
    provider: github
    allowedUsers:
      - team: engineering

Data Anonymization

# Atmosly runs anonymization on database snapshots
from faker import Faker
fake = Faker()

UPDATE users SET
  email = fake.email(),
  phone = fake.phone_number(),
  ssn = 'XXX-XX-XXXX',
  address = fake.address()
WHERE environment = 'preview';

Best Practices

  1. Start small: Begin with one service, expand to full stack
  2. Automate cleanup: Delete preview envs on PR merge/close
  3. Use realistic data: Production snapshots (anonymized) catch more bugs than fixtures
  4. Monitor costs: Set alerts for preview env spending
  5. Limit lifetime: Max 7-14 days to prevent abandoned envs
  6. Share URLs: Post preview links in PR comments for visibility
  7. Run tests: Automate E2E tests in preview before merge
  8. Secure access: Use basic auth or OAuth to prevent public access

Conclusion

Preview environments accelerate development by providing instant, isolated testing environments for every feature. Atmosly's feature environment support makes this practical through Kubernetes-native automation, cost optimization, and database snapshot management.

Key benefits:

  • Instant provisioning: 2-5 minutes from PR to live URL
  • 🔒 Full isolation: No conflicts with other developers
  • 💰 Cost-optimized: Auto-deletion, right-sizing, spot instances
  • 🗄️ Database snapshots: Production-like data (anonymized)
  • 🔗 Seamless CI/CD: GitHub Actions, GitLab CI integration

Ready to enable preview environments? Get started with Atmosly to automatically create feature environments for every pull request.

Frequently Asked Questions

What's the difference between preview environments and staging?
Staging is a shared environment that all developers use for testing before production. This creates bottlenecks (only one team can test at a time), state conflicts (your changes interfere with others), and low confidence (failures might be from others' code, not yours). Preview environments create isolated, disposable environments for each pull request—unlimited parallelization, zero conflicts, and high confidence that tests reflect only your changes. Staging is good for final integration testing before release; preview environments are for rapid feedback during development. Many teams use both: preview envs for PR validation, staging for release candidates.
How does Atmosly handle databases for preview environments?
Atmosly offers three database strategies: 1) Snapshot: Clones production database with automatic anonymization of PII (emails, SSNs, payment data) using configurable rules. Fast (uses storage snapshots, not full copies) and realistic. 2) Seeded: Starts with empty database and runs seed scripts to populate test data. Fast, predictable, but less realistic. 3) Shared: All preview envs use shared staging database with isolated schemas (e.g., preview_pr_456). Cost-effective but less isolated. Most teams use snapshots for high-fidelity testing. Atmosly handles provisioning (2-5 min), credential injection into Kubernetes secrets, and automatic cleanup on PR close to prevent cost runaway.
Aren't preview environments expensive?
They can be, but Atmosly includes cost controls: 1) Right-sizing: Preview envs use smaller instances (250m CPU vs 1000m in prod), 2) Auto-deletion: Deleted automatically when PR merges/closes or after 7 days max, 3) Idle detection: Scale to zero after 2h of no traffic, delete after 24h idle, 4) Scheduled shutdowns: Turn off nights/weekends for dev branches, 5) Spot instances: Use spot for preview databases (70% cheaper), 6) Shared resources: Use staging Elasticsearch/Kafka instead of provisioning per preview. Typical cost: $5-20/month per active preview env, vs hours of developer time wasted on staging conflicts. ROI is positive for teams with 5+ developers.
Can preview environments handle microservices?
Yes, Atmosly supports multi-service preview environments. You can deploy entire stacks (frontend, API gateway, multiple backend services, databases, caches) in each preview namespace. Two approaches: 1) Full stack: Deploy all services from their respective feature branches. Useful when changes span multiple services. 2) Hybrid: Deploy only changed service(s) in preview, route to staging for unchanged services via service mesh or DNS. This saves costs—if you're only changing the payment service, deploy just that; frontend and other services point to staging versions. Atmosly config lets you declare dependencies and automatically wires up networking.
How do I secure preview environments?
Preview environments are public by default (accessible via URL), so security is critical: 1) Basic auth: Atmosly generates random password per preview, posted to PR comments. Simple but effective. 2) OAuth: Integrate with GitHub/GitLab OAuth—only team members can access. 3) IP allowlisting: Restrict to corporate VPN or office IPs. 4) Data anonymization: CRITICAL—always anonymize production data snapshots (PII, payment info, health data). Atmosly provides built-in anonymization rules using Faker. 5) Network policies: Isolate preview namespaces from production. 6) Time-limited access: Auto-delete after 7 days. 7) Audit logs: Track who accessed which preview envs. Never expose unanonymized production data in previews—compliance risk.