Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Infrastructure Promotion Pipelines (dev to prod)

By Kokil Thapa | Last reviewed: September 2026

Infrastructure promotion pipelines (dev to prod) are the controlled path that moves application code, server config, and infrastructure definitions from a developer laptop into live production. A broken promotion shows up as downtime, leaked secrets, or a staging stack that no longer matches prod. On real client projects I run with Linux system administration and Git-based deploys, the fix is rarely “deploy faster.” It is clearer stages, automated checks, and gates humans only touch when risk warrants it. This guide walks through how to design, automate, and operate that path in 2026.

What is an infrastructure promotion pipeline from dev to prod?

An infrastructure promotion pipeline is a sequence of environments plus the automation that moves artifacts between them. “Artifact” means more than a Git tag. It can be a Docker image, a Terraform plan output, a Composer build, or a Deployer release tarball. Each stage runs the same class of checks with stricter rules as you get closer to users.

Promotion is not the same as continuous deployment. You can promote infrastructure daily to dev and weekly to prod. The pipeline still defines how a change travels, even when humans click “approve.”

Promotion Pipeline OverviewDevFast feedbackStagingProd-like testsProductionLive trafficQuality gates at each hopLint · Unit tests · IaC plan · Security scanManual approval · Smoke tests · Rollback tag
Infrastructure promotion pipelines (dev to prod) move artifacts left to right through gated environments.

Think in three layers. Application code (PHP, JavaScript, Blade templates). Runtime config (Nginx, PHP-FPM pools, Redis). Infrastructure definitions (Terraform, CloudFormation, or hand-maintained server roles). A mature pipeline promotes all three in a defined order, usually infra first, then app, then cache warm-up.

If you already treat servers as cattle, read immutable vs mutable infrastructure before wiring stages. Immutable images simplify promotion because each environment receives the same artefact hash. Mutable servers need drift checks so staging still mirrors prod.

Promotion vs deployment

Deployment is applying a version to one environment. Promotion is the policy that decides when that version may leave dev. Pipelines encode that policy in YAML, Jenkinsfile, or GitLab CI rules so teams do not rely on tribal knowledge.

How do you design environment stages for a dev-to-prod pipeline?

Start with the minimum set of environments your team can actually maintain. Many Nepal agencies run dev, staging, and prod on one VPS with separate databases. That is valid if staging uses the same PHP 8.3 or 8.4 runtime and matching extensions as prod.

A common mistake is a “QA” box that runs PHP 8.2 while production runs 8.4. Promotion then lies to you. Align versions with your framework baseline: Laravel 13 needs PHP 8.3+, Laravel 12 needs 8.2+. Document that matrix in the repo README and enforce it in CI.

  1. Dev — feature branches, optional shared dev, fast deploys, synthetic data.
  2. Staging — release branch only, prod-like sizing where budget allows, anonymised prod snapshots or realistic fixtures.
  3. Production — tagged releases, manual or automated approval, monitored rollouts, documented rollback.

For web development projects with booking or payment flows, add an integration stage that hits sandbox gateways (Stripe test mode, eSewa sandbox). Do not skip it because “staging is slow.” Payment regressions cost more than an extra five-minute job.

StageTypical triggerDataApproval
DevPush to feature branchSeeders / fixturesNone
StagingMerge to mainAnonymised copyOptional peer review
ProductionGit tag or release branchLive dataManual or change window

Namespace resources per environment: separate S3 buckets, RDS instances, or at minimum distinct database names and Redis DB indexes. Shared secrets across stages are a frequent source of staging emails hitting real customers.

How do you automate infrastructure promotion with CI/CD?

Pick a CI runner that matches your host. GitLab CI on self-managed GitLab, GitHub Actions for GitHub-hosted repos, or Jenkins when you need plugins for legacy stacks. The pipeline file lives in version control; promotion rules live beside application code so they undergo review too.

I maintain several legal-tech and translation sites on a shared EC2 box using Deployer 7 and GitLab CI. The pattern is repeatable for Laravel 12/13 apps: lint and test on push, build assets in CI, deploy to staging on main, deploy to prod only on tag. See the step-by-step GitLab CI pipeline for Laravel for a concrete starting point.

CI/CD Promotion StagesLintTestBuildPlan IaCDeployEnvironment-specific jobsdeploy:staging — auto on main mergedeploy:production — manual on v* tagpost-deploy smoke — curl health, queue pingFailed job blocks promotion
Automated CI/CD jobs enforce infrastructure promotion pipelines from dev to prod with blocking gates.

Example GitLab CI promotion rules

GitLab CI uses rules or only/except (legacy) to map branches and tags to environments. Official docs: GitLab CI environments.

# .gitlab-ci.yml (excerpt)
stages:
  - validate
  - test
  - build
  - deploy

variables:
  COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.composer-cache"

phpunit:
  stage: test
  image: php:8.4-cli
  script:
    - composer install --no-interaction
    - php artisan test

deploy_staging:
  stage: deploy
  environment:
    name: staging
    url: https://staging.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  script:
    - dep deploy staging -vvv

deploy_production:
  stage: deploy
  environment:
    name: production
    url: https://example.com
  rules:
    - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
  when: manual
  script:
    - dep deploy production -vvv
    - curl -fsS https://example.com/health

Deployer zero-downtime releases

Deployer 7 symlinks current to a new release directory, keeps shared .env and storage/, and reloads PHP-FPM so opcache picks up code. Documented at Deployer 7 getting started. After symlink swap, run php artisan migrate --force only when migrations are backward-compatible, or run them before traffic shifts if they are not.

# deploy.php (excerpt)
namespace Deployer;

require 'recipe/laravel.php';

set('repository', 'git@gitlab.com:org/app.git');
set('keep_releases', 5);

host('staging.example.com')
    ->set('remote_user', 'deploy')
    ->set('deploy_path', '/var/www/staging');

host('production.example.com')
    ->set('remote_user', 'deploy')
    ->set('deploy_path', '/var/www/production');

after('deploy:symlink', 'artisan:optimize:clear');

For Terraform or OpenTofu stacks, split plan and apply jobs per environment. Store remote state per env in separate buckets or workspaces. Tie promotion to approved merge requests, as described in Terraform with Azure DevOps pipelines and the broader infrastructure as code overview.

Local parity before promotion

Developers should reproduce prod services locally. Laravel Sail with Docker works well for PHP 8.3+ and MySQL 8.4. See local Laravel dev with Sail. Validate JSON API payloads in CI with a JSON formatter step or schema test so bad config never leaves dev.

What are the best practices for secrets, approvals, and compliance?

Secrets never belong in Git, even in private repos. CI systems inject them at runtime from masked variables, HashiCorp Vault, or cloud secret managers. Read manage secrets safely in pipelines before wiring production keys.

Use different credentials per environment. Staging may call payment sandboxes with test keys. Production keys live only in the prod job scope. Rotate keys when staff leave; update CI variables the same day.

  • Approval gates — require manual job for prod or change-advisory for regulated clients.
  • Audit trail — GitLab environments and Jenkins build history show who promoted what.
  • Idempotency — replays should not double-create resources; see idempotency in infrastructure automation.
  • Drift detection — scheduled terraform plan that fails on unexpected diff.
Mutable vs Immutable PromotionMutable VPSSSH + Deployer symlinkConfig drift riskCheaper for SMB sitesPHP-FPM reload requiredGood fit: Laravel on VPSImmutable imageBuild once, promote hashIdentical dev/stage/prodHigher setup costFast rollback via tagGood fit: containers/K8s
Choose mutable or immutable promotion based on team size, budget, and drift tolerance.

On a legal-tech portal I built, document uploads and client notifications mean prod promotion waits for a smoke test that hits S3-compatible storage and the mail queue. Skipping that test saved five minutes once and cost an hour of log tracing.

Align promotion with business hours in Nepal if your users are local. A Friday evening prod push before Dashain traffic is avoidable. Schedule tags or use maintenance windows documented in support and maintenance runbooks.

How do you test and validate before promoting to production?

Automated tests are the first gate. PHPUnit or Pest for Laravel, plus static analysis (PHPStan, Larastan). Add integration tests that boot the app against a real MySQL 8.4 or MariaDB 12.3 instance in CI, not SQLite-only suites that hide JSON column bugs.

Infrastructure code deserves tests too. Terratest, terraform validate, tflint, and policy checks (OPA, Sentinel) belong in the validate stage. Follow build pipeline automation best practices so flaky tests get fixed instead of disabled.

Post-deploy smoke tests should be boring: HTTP 200 on /health, queue worker heartbeat, Redis ping, disk space above threshold. Fail the pipeline if any check fails within five minutes of deploy. That beats learning from user reports.

For enterprise apps with long QA cycles, see enterprise application development patterns: feature flags decouple deploy from release so code sits in prod dark until product flips the flag.

How do you roll back failed infrastructure promotions safely?

Every promotion path needs a rollback that does not require guessing which Git commit was live. Deployer keeps five releases; dep rollback production swaps the symlink back. Tag Docker images and Terraform state versions the same way.

Database migrations are the hard part. Prefer expand-contract migrations: add nullable columns first, deploy code, backfill, then remove old columns in a later release. Never ship destructive migrations in the same release as a Friday deploy unless you enjoy restore drills.

Rollback Decision TreeProd deploy failed?App only bugdep rollbackBad migrationRestore DB snapshotReload PHP-FPMReplay WAL backupDocument incident + fix pipeline
Rollback paths differ for application code versus schema changes in infrastructure promotion pipelines.

Keep nightly database dumps on prod and test restores quarterly. A backup you never restored is wishful thinking. For hosting setup and DNS cutovers, coordinate with domain registration and hosting so TTL and SSL lines up with promotion windows.

Projects like Adventure Third Pole Trek and Notary Kathmandu share a Deployer 7 pipeline on common infrastructure. One fixed cron path or wrong PHP binary breaks every site on that box. Centralise pipeline templates in a private repo or CI include file so fixes propagate once.

If you outgrow a single server, promotion moves toward blue-green or canary deploys behind a load balancer. The gate logic stays the same; only the transport changes. Jenkins users can mirror the same stages with a declarative pipeline tutorial as a reference.

Key Takeaways

  • Define dev, staging, and prod with matching PHP, database, and extension versions before automating anything.
  • Encode promotion rules in CI YAML so only vetted branches and tags reach production.
  • Separate secrets per environment and require manual approval for prod deploy jobs when risk is high.
  • Run plan, test, deploy, and smoke stages in order; a failed job must block the next environment.
  • Keep rollback mechanical: symlink swap for apps, tagged images for containers, tested DB restores for migrations.
  • Document the pipeline beside the code and review changes with every feature merge.

People Also Ask

What is the difference between continuous delivery and promotion pipelines?

Continuous delivery means every commit could go to prod but might wait for a human. A promotion pipeline defines the exact environment order and gates. You can use promotion stages inside a continuous delivery workflow without auto-deploying every merge.

How many environments do small teams need?

Two runnable environments plus local dev is enough for many SMB sites: staging and production. Add a shared dev only when QA load exceeds what laptops can host. Extra environments cost money and drift if unmaintained.

Should infrastructure and application share one pipeline?

Often yes, with ordered stages: validate Terraform, apply to staging infra, deploy app, run smoke tests, repeat for prod. Split pipelines when infra changes are rare and owned by a different team, but keep promotion rules aligned.

How do you promote database schema changes safely?

Use backward-compatible migrations, deploy application code that works with both old and new schema, then clean up in a follow-up release. Never promote destructive DDL and application code in a single step without a verified restore path.

Ship promotion pipelines your team can run at 2 a.m.

Strong infrastructure promotion pipelines (dev to prod) turn deployment from a hero task into a repeatable checklist. Start with environment parity, wire GitLab CI or your chosen runner, protect secrets, and prove rollback before you need it. If you want help auditing an existing Laravel or WordPress deploy path, review our portfolio or reach out via contact us for a practical pipeline review. For deeper CI patterns, browse technical blog guides or pair promotion work with testing and optimization so each stage earns the right to touch production.

Frequently Asked Questions

A controlled sequence of environments—dev, staging, production—plus automation that moves validated artifacts between stages using CI/CD jobs, infrastructure-as-code, and approval gates so only tested changes reach live systems.

Deployment applies one version to a single environment. Promotion is the policy that decides when that version may leave dev, encoded in pipeline YAML or rules so teams do not rely on tribal knowledge.

Two runnable environments plus local dev is enough for many SMB sites: staging and production. Add a shared dev only when QA load exceeds what laptops can host; extra environments cost money and drift if unmaintained.

Think in three layers: application code (PHP, JavaScript, Blade), runtime config (Nginx, PHP-FPM pools, Redis), and infrastructure definitions (Terraform, CloudFormation, or hand-maintained server roles). A mature pipeline promotes all three in order—usually infra first, then app, then cache warm-up—so staging still mirrors production.

Start with the minimum set your team can maintain. Many Nepal agencies run dev, staging, and prod on one VPS with separate databases, which is valid if staging matches prod PHP and extensions. Dev takes feature branches with seed data; staging takes release merges with anonymised prod snapshots; production takes tagged releases with manual or automated approval and monitored rollouts. Namespace resources per environment—separate buckets, databases, or Redis DB indexes—to avoid staging emails hitting real customers.

Put the pipeline file in version control beside application code. A repeatable Laravel pattern: lint and test on push, build assets in CI, deploy to staging on main, deploy to prod only on a version tag with a manual job. Deployer 7 symlinks current to a new release, keeps shared .env and storage/, reloads PHP-FPM for opcache, and runs migrations only when backward-compatible. Map branches and tags to environments using GitLab CI rules and environment definitions.

Match PHP runtime and extensions across stages—Laravel 13 needs PHP 8.3+, Laravel 12 needs 8.2+. A QA box on PHP 8.2 while production runs 8.4 makes promotion lie to you. Document the version matrix in the repo README and enforce it in CI. For mutable servers, run drift checks so staging mirrors prod; immutable images simplify promotion because each environment receives the same artefact hash.

Often yes, with ordered stages: validate Terraform, apply to staging infra, deploy the app, run smoke tests, then repeat for production. Split pipelines when infra changes are rare and owned by a different team, but keep promotion rules aligned so application deploys never outrun infrastructure readiness. For Terraform or OpenTofu, split plan and apply jobs per environment and store remote state in separate buckets or workspaces.

Continuous delivery means every commit could go to production but might wait for a human. A promotion pipeline defines the exact environment order and gates—dev, staging, prod—with stricter checks closer to users. You can use promotion stages inside a continuous delivery workflow without auto-deploying every merge. Promotion is not the same as continuous deployment; you can promote to dev daily and prod weekly while the pipeline still defines how changes travel.

Secrets never belong in Git, even in private repos. CI systems inject them at runtime from masked variables, HashiCorp Vault, or cloud secret managers. Use different credentials per environment—staging calls payment sandboxes with test keys, production keys live only in the prod job scope. Rotate keys when staff leave and update CI variables the same day. Shared secrets across stages are a frequent source of staging actions hitting real customers or live payment gateways.

Automated tests are the first gate: PHPUnit or Pest for Laravel, plus static analysis with PHPStan or Larastan. Run integration tests against a real MySQL 8.4 or MariaDB 12.3 instance in CI, not SQLite-only suites that hide JSON column bugs. Infrastructure code gets terraform validate, tflint, and policy checks in the validate stage. Post-deploy smoke tests should confirm HTTP 200 on /health, queue worker heartbeat, Redis ping, and adequate disk space—fail the pipeline within five minutes rather than learning from user reports.

Every promotion path needs rollback that does not require guessing which commit was live. Deployer keeps five releases; dep rollback production swaps the symlink back. Tag Docker images and Terraform state versions the same way. Database migrations are the hard part—prefer expand-contract migrations: add nullable columns first, deploy code, backfill, then remove old columns later. Never ship destructive migrations in the same release as a risky deploy unless you have a verified restore path. Test nightly database restores quarterly.

Use backward-compatible migrations and deploy application code that works with both old and new schema, then clean up in a follow-up release. Add nullable columns first, deploy code that reads them, backfill data, and only then drop old columns. Never promote destructive DDL and application code in a single step without a tested restore path. Rollback paths differ for application code versus schema changes, so plan both before the promotion window opens.

Require a manual CI job for production when risk is high—regulated clients, payment flows, document uploads, or client notifications. GitLab environments and Jenkins build history provide an audit trail showing who promoted what. Align promotion with business hours if users are local; a Friday evening prod push before Dashain traffic is avoidable. Schedule tags or use documented maintenance windows. Promotion can be automated for low-risk changes but human gates belong where downtime or leaked secrets would hurt most.

Keep post-deploy checks boring and fast: HTTP 200 on /health, queue worker heartbeat, Redis ping, and disk space above threshold. Fail the pipeline if any check fails within five minutes of deploy. On a legal-tech portal, a smoke test should hit S3-compatible storage and the mail queue before prod traffic shifts—skipping that once saved five minutes and cost an hour of log tracing. For booking or payment flows, add an integration stage against sandbox gateways like Stripe test mode or eSewa sandbox before production promotion.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: