---
title: Environment Strategy & Initial Provisioning | Shopware Community Hub
description: >-
  Learn how to design effective environment strategies and provision initial
  services for your PaaS Shopware deployment.
canonical_url: 'https://hub.shopware.com/learn/unit/paas-environment-strategy'
---

# Environment Strategy & Initial Provisioning

<LearningObjectives>

- Design comprehensive environment strategies for development, staging, and production.
- Implement feature environments with branch-based previews.
- Provision and configure essential services (database, Redis, Elasticsearch).
- Understand environment-specific configuration management.
- Set up automated environment provisioning workflows.

</LearningObjectives>

# Environment Strategy & Initial Provisioning

Now that you have your repository set up and access configured, it's time to design the environment strategy to support development workflows and ensure smooth deployments.

## Environment Planning: Dev, Staging, Production

### Environment Architecture Overview

A robust PaaS strategy typically includes multiple environment types, each serving specific purposes:

![Deployment Architecture](assets/deployment-architecture.png)

*Figure: PaaS Deployment Architecture showing the relationship between different environments and the deployment flow from development through staging to production, including feature environments for branch-based previews.*

### Development Environment

The development environment should mirror production while allowing for rapid iteration:

#### .platform/environments/development.yaml

```yaml
name: development
type: development

variables:
  env:
    APP_ENV: 'dev'
    APP_DEBUG: 'true'
    SHOPWARE_ES_ENABLED: 'false'
    SHOPWARE_ES_INDEXING_ENABLED: 'false'
    SHOPWARE_HTTP_CACHE_ENABLED: 'false'
    SHOPWARE_HTTP_DEFAULT_TTL: '0'

resources:
  app:
    size: 'S'
    disk: 1024
  
services:
  database:
    type: 'mariadb:10.6'
    disk: 512
  redis:
    type: 'redis:7.0'
    size: 'XS'
```

#### Development Environment Characteristics

- **Fast deployment cycles** (< 2 minutes).
- **Debug mode enabled** for detailed error reporting.
- **Reduced resource allocation** to minimize costs.
- **Simplified service configuration** for quick setup.
- **Hot-reloading capabilities** where possible.

### Staging Environment

Staging should closely replicate production for final testing:

#### .platform/environments/staging.yaml

```yaml
name: staging
type: staging

variables:
  env:
    APP_ENV: 'prod'
    APP_DEBUG: 'false'
    SHOPWARE_ES_ENABLED: 'true'
    SHOPWARE_ES_INDEXING_ENABLED: 'true'
    SHOPWARE_HTTP_CACHE_ENABLED: 'true'
    SHOPWARE_HTTP_DEFAULT_TTL: '3600'

resources:
  app:
    size: 'M'
    disk: 2048
  
services:
  database:
    type: 'mariadb:10.6'
    disk: 1024
  redis:
    type: 'redis:7.0'
    size: 'S'
  elasticsearch:
    type: 'elasticsearch:7.17'
    disk: 512
```

#### Staging Environment Characteristics

- **Production-like configuration** for accurate testing.
- **Performance testing capabilities** with realistic data volumes.
- **Integration testing** with external services.
- **User acceptance testing** environment.
- **Security testing** with production-level configurations.

### Production Environment

Production requires maximum stability and performance:

#### .platform/environments/production.yaml

```yaml
name: production
type: production

variables:
  env:
    APP_ENV: 'prod'
    APP_DEBUG: 'false'
    SHOPWARE_ES_ENABLED: 'true'
    SHOPWARE_ES_INDEXING_ENABLED: 'true'
    SHOPWARE_HTTP_CACHE_ENABLED: 'true'
    SHOPWARE_HTTP_DEFAULT_TTL: '3600'
    SHOPWARE_CACHE_ID: 'production'

resources:
  app:
    size: 'L'
    disk: 4096
  
services:
  database:
    type: 'mariadb:10.6'
    disk: 4096
  redis:
    type: 'redis:7.0'
    size: 'M'
  elasticsearch:
    type: 'elasticsearch:7.17'
    disk: 2048

backup:
  schedule: '0 2 * * *'  # Daily at 2 AM
  retention: 30          # Keep 30 days
```

#### Production Environment Characteristics

- **High availability** with redundancy.
- **Optimized performance** configurations.
- **Comprehensive monitoring** and alerting.
- **Automated backups** and disaster recovery.
- **Security hardening** and compliance.

## Feature Environments: Branch-Based Previews

### Automatic Feature Environment Creation

Feature environments allow developers to test changes in isolation before merging:

#### .platform/environments/feature.yaml

```yaml
name: feature-*
type: development
parent: staging

variables:
  env:
    APP_ENV: 'dev'
    APP_DEBUG: 'true'
    FEATURE_BRANCH: '$PLATFORM_BRANCH'

resources:
  app:
    size: 'XS'
    disk: 512

services:
  database:
    type: 'mariadb:10.6'
    disk: 256
    # Clone from parent environment
    clone: 'parent'
  redis:
    type: 'redis:7.0'
    size: 'XS'

hooks:
  deploy: |
    set -e
    # Sanitize data for feature environment
    bin/console database:create-migration --all
    bin/console cache:clear
    bin/console theme:compile
```

### GitHub Actions Integration

Automate feature environment creation with GitHub Actions:

#### .github/workflows/feature-environment.yml

```yaml
name: Feature Environment

on:
  pull_request:
    types: [opened, synchronize]
    branches: [main, develop]

jobs:
  deploy-feature:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Setup Platform CLI
        run: |
          curl -sS https://platform.sh/cli/installer | php
          export PATH="$HOME/.platformsh/bin:$PATH"

      - name: Deploy Feature Environment
        env:
          PLATFORM_PROJECT_ID: ${{ secrets.PLATFORM_PROJECT_ID }}
          PLATFORM_API_TOKEN: ${{ secrets.PLATFORM_API_TOKEN }}
        run: |
          platform environment:activate ${{ github.head_ref }} --parent=staging
          platform push --target=${{ github.head_ref }}

      - name: Comment PR with Environment URL
        uses: actions/github-script@v6
        with:
          script: |
            const branch = context.payload.pull_request.head.ref;
            const url = `https://${branch}-${process.env.PLATFORM_PROJECT_ID}.platform.sh`;
            
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `🚀 Feature environment deployed: [${url}](${url})`
            });
```

### Feature Environment Benefits

- **Isolated testing** without affecting other environments.
- **Parallel development** of multiple features.
- **Stakeholder previews** before code review.
- **Automated cleanup** when branches are deleted.
- **Cost-effective** with automatic scaling.

## Service Initialization

### Database Configuration

#### MariaDB Setup for Different Environments

```yaml
# .platform/services/database.yaml
database:
  type: mariadb:10.6
  disk: 2048
  configuration:
    schemas:
      - shopware
    endpoints:
      mysql:
        default_schema: shopware
        privileges:
          shopware: admin
```

#### Database Initialization Script

```bash
#!/bin/bash
# scripts/init-database.sh
# This script initializes the database for different environments
# It's called automatically during the deploy hook

set -e

echo "Initializing database for environment: $PLATFORM_ENVIRONMENT"

# Wait for database to be ready
# This ensures MariaDB service is fully started before proceeding
until bin/console dbal:run-sql "SELECT 1" > /dev/null 2>&1; do
  echo "Waiting for database..."
  sleep 2
done

# Run migrations
# Creates migration files for all installed plugins and core updates
bin/console database:create-migration --all

# Install or update schema based on environment
if [ "$PLATFORM_ENVIRONMENT" = "production" ]; then
  echo "Production environment - running migrations only"
  # Only run migrations in production to preserve data
  bin/console database:migrate --all
else
  echo "Non-production environment - installing fresh schema"
  # Fresh install for dev/staging environments
  bin/console system:install --create-database --basic-setup
fi

echo "Database initialization complete"
```

<Callout title="Script Usage" type="info">

This script is automatically executed during the deploy hook defined in `.platform/applications.yaml`. It ensures the database is properly initialized for each environment type.

</Callout>

### Redis Configuration

#### Redis for Session and Cache Storage

```yaml
# .platform/services/redis.yaml
redis:
  type: redis:7.0
  configuration:
    maxmemory_policy: allkeys-lru
    save: 900 1
```

#### Redis Configuration in Shopware

```yaml
# config/packages/prod/framework.yaml
framework:
  session:
    handler_id: 'redis://redis.internal:6379/0'
  cache:
    app: cache.adapter.redis
    system: cache.adapter.redis
    pools:
      cache.adapter.redis:
        adapter: cache.adapter.redis
        provider: 'redis://redis.internal:6379/1'
```

### Elasticsearch Configuration

#### Elasticsearch Service Setup

```yaml
# .platform/services/elasticsearch.yaml
elasticsearch:
  type: elasticsearch:7.17
  disk: 1024
  configuration:
    plugins:
      - analysis-icu
      - analysis-phonetic
```

#### Shopware Elasticsearch Configuration

```yaml
# config/packages/prod/shopware.yaml
shopware:
  elasticsearch:
    enabled: true
    hosts: 'elasticsearch.internal:9200'
    index_prefix: 'shopware'
    throw_exception: true
```

### Service Health Checks

#### Automated Service Monitoring

```bash
#!/bin/bash
# scripts/health-check.sh

set -e

echo "Performing health checks..."

# Database health check
if ! bin/console dbal:run-sql "SELECT 1" > /dev/null 2>&1; then
  echo "❌ Database connection failed"
  exit 1
fi
echo "✅ Database connection successful"

# Redis health check
if ! redis-cli -h redis.internal ping > /dev/null 2>&1; then
  echo "❌ Redis connection failed"
  exit 1
fi
echo "✅ Redis connection successful"

# Elasticsearch health check (if enabled)
if [ "$SHOPWARE_ES_ENABLED" = "true" ]; then
  if ! curl -s http://elasticsearch.internal:9200/_cluster/health > /dev/null; then
    echo "❌ Elasticsearch connection failed"
    exit 1
  fi
  echo "✅ Elasticsearch connection successful"
fi

echo "🎉 All services healthy"
```

## Environment-Specific Configuration Management

### Configuration Strategy

Use environment variables and configuration files to manage differences:

#### Environment Variable Mapping

```yaml
# .platform/variables.env
# Development
APP_ENV=dev
APP_DEBUG=true
SHOPWARE_ES_ENABLED=false

# Staging
APP_ENV=prod
APP_DEBUG=false
SHOPWARE_ES_ENABLED=true

# Production
APP_ENV=prod
APP_DEBUG=false
SHOPWARE_ES_ENABLED=true
SHOPWARE_CACHE_ID=production
```

#### Dynamic Configuration Loading

```php
<?php
// config/services.php

use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $container): void {
    $environment = $_ENV['PLATFORM_ENVIRONMENT'] ?? 'local';
    
    // Load environment-specific configurations
    $container->import("packages/{$environment}/*.yaml");
    
    // Load service-specific configurations
    if (isset($_ENV['PLATFORM_RELATIONSHIPS'])) {
        $relationships = json_decode(base64_decode($_ENV['PLATFORM_RELATIONSHIPS']), true);
        
        // Configure database from relationships
        if (isset($relationships['database'])) {
            $db = $relationships['database'][0];
            $container->parameters()->set('database_url', sprintf(
                'mysql://%s:%s@%s:%d/%s',
                $db['username'],
                $db['password'],
                $db['host'],
                $db['port'],
                $db['path']
            ));
        }
    }
};
```

## Automated Provisioning Workflows

### Infrastructure as Code

#### Terraform Configuration for Multi-Environment Setup

```hcl
# infrastructure/environments.tf
variable "environments" {
  type = map(object({
    app_size = string
    db_size  = number
    redis_size = string
  }))
  
  default = {
    development = {
      app_size = "S"
      db_size = 512
      redis_size = "XS"
    }
    staging = {
      app_size = "M"
      db_size = 1024
      redis_size = "S"
    }
    production = {
      app_size = "L"
      db_size = 4096
      redis_size = "M"
    }
  }
}

resource "platform_environment" "environments" {
  for_each = var.environments
  
  project_id = var.project_id
  name = each.key
  type = each.key == "production" ? "production" : "development"
  
  machine_type = each.value.app_size
  storage = each.value.db_size
}
```

### Deployment Pipeline

#### Complete CI/CD Pipeline

```yaml
# .github/workflows/deploy.yml
name: Deploy to Environments

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
      - name: Install dependencies
        run: composer install
      - name: Run tests
        run: vendor/bin/phpunit

  deploy-staging:
    needs: test
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Deploy to staging
        env:
          PLATFORM_PROJECT_ID: ${{ secrets.PLATFORM_PROJECT_ID }}
          PLATFORM_API_TOKEN: ${{ secrets.PLATFORM_API_TOKEN }}
        run: |
          platform push --target=staging
          platform environment:synchronize staging --no-wait

  deploy-production:
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v3
      - name: Deploy to production
        env:
          PLATFORM_PROJECT_ID: ${{ secrets.PLATFORM_PROJECT_ID }}
          PLATFORM_API_TOKEN: ${{ secrets.PLATFORM_API_TOKEN }}
        run: |
          platform push --target=production
          platform environment:synchronize production --no-wait
```

## Best Practices and Troubleshooting

### Environment Management Best Practices

1. **Consistent naming conventions** across all environments.
2. **Automated environment provisioning** to reduce manual errors.
3. **Regular environment synchronization** to keep staging current.
4. **Resource optimization** based on environment usage patterns.
5. **Security isolation** between environments.

### Common Issues and Solutions

#### Environment Provisioning Failures

```bash
# Check environment status
platform environment:list

# View deployment logs
platform log --environment=staging

# Restart failed deployment
platform redeploy --environment=staging
```

#### Service Connection Issues

```bash
# Test service connectivity
platform ssh --environment=staging
redis-cli -h redis.internal ping
mysql -h database.internal -u user -p

# Check service status
platform service:list --environment=staging
```

#### Configuration Synchronization Problems

```bash
# Sync environment variables
platform variable:list --environment=staging
platform variable:set APP_ENV prod --environment=staging

# Sync configuration files
platform mount:list --environment=staging
platform rsync staging:files/ ./local-files/
```

## Next Steps

In the next learning unit, we'll focus on the essential tooling and validation processes to make your project deployment-ready and to maintain and scale PaaS environments effectively.
