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
| Aspect | Shared Staging | Preview Environments |
|---|---|---|
| Parallelization | One staging → bottleneck | Unlimited parallel testing |
| Isolation | Shared state → conflicts | Fully isolated per PR |
| Test confidence | Low (others' changes interfere) | High (only your changes) |
| Cleanup | Manual or never | Automatic on PR close |
| Database | Shared (risky) | Isolated snapshot |
| Setup time | Manual coordination | Automatic (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
Start small: Begin with one service, expand to full stackAutomate cleanup: Delete preview envs on PR merge/closeUse realistic data: Production snapshots (anonymized) catch more bugs than fixturesMonitor costs: Set alerts for preview env spendingLimit lifetime: Max 7-14 days to prevent abandoned envsShare URLs: Post preview links in PR comments for visibilityRun tests: Automate E2E tests in preview before mergeSecure 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.