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.

AWS CloudFormation: Infrastructure as Code on AWS

By Kokil Thapa | Last reviewed: August 2026

AWS CloudFormation: Infrastructure as Code on AWS lets you define entire cloud environments in declarative YAML or JSON templates, eliminating manual console clicks and configuration drift. For teams building production web systems, this means reproducible deployments, version-controlled infrastructure, and consistent environments from development to production. Whether you are provisioning a simple Laravel application stack or a complex multi-tier eCommerce platform, understanding AWS cloud hosting fundamentals alongside CloudFormation is essential for reliable operations.

What is AWS CloudFormation: Infrastructure as Code on AWS and why use it?

AWS CloudFormation: Infrastructure as Code on AWS transforms infrastructure provisioning from manual, error-prone console operations into automated, auditable code artifacts. Instead of clicking through the AWS Management Console to create EC2 instances, RDS databases, VPCs, and security groups, you write a template that describes your desired state. CloudFormation then handles the orchestration, dependency resolution, and resource creation in the correct order.

In my experience working on production Laravel applications deployed to AWS, the shift to CloudFormation eliminated an entire class of deployment failures caused by environment inconsistencies. When every environment is defined by the same template, "works on my machine" problems disappear. The template becomes the single source of truth for what infrastructure exists, how it is configured, and how components relate to each other.

YAML TemplateResources:- VPC- EC2 Instance- RDS Database- Security GroupsCloudFormation ServiceTemplate ValidationDependency ResolutionResource OrchestrationRollback on FailureDrift DetectionLive AWS StackVPC: vpc-0abc123EC2: i-0def456RDS: mydb-instanceSG: sg-0ghi789CREATE_COMPLETE
AWS CloudFormation Infrastructure as Code workflow: YAML template defines desired state, CloudFormation orchestrates provisioning, resulting stack reflects live resources

The core value proposition extends beyond automation. CloudFormation provides built-in change sets that preview modifications before applying them, stack policies that prevent accidental deletion of critical resources, and cross-stack references that enable modular architecture. For Nepal-based businesses evaluating cloud hosting options, CloudFormation reduces operational overhead significantly compared to manually managed infrastructure, even when team size is small.

How do you write your first AWS CloudFormation YAML template?

Writing effective CloudFormation templates requires understanding the YAML structure, resource types, and intrinsic functions. Start with a minimal viable template and expand incrementally rather than attempting to model everything at once.

Basic template structure and required sections

Every CloudFormation template includes these sections:

  • AWSTemplateFormatVersion — specifies the template format (use 2010-09-09)
  • Description — human-readable explanation of what the stack provisions
  • Parameters — input values that make templates reusable across environments
  • Resources — the only required section; defines AWS resources to create
  • Outputs — values returned after stack creation (endpoints, IDs, ARNs)
AWSTemplateFormatVersion: '2010-09-09'
Description: Laravel application stack with RDS MySQL

Parameters:
  Environment:
    Type: String
    AllowedValues: [dev, staging, production]
    Default: dev
  DBPassword:
    Type: String
    NoEcho: true
    MinLength: 12

Resources:
  AppSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow HTTP and SSH
      VpcId: !ImportValue SharedVPC-ID
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 10.0.0.0/8

  AppDatabase:
    Type: AWS::RDS::DBInstance
    Properties:
      DBInstanceClass: db.t3.micro
      Engine: mysql
      EngineVersion: '8.0'
      MasterUsername: admin
      MasterUserPassword: !Ref DBPassword
      AllocatedStorage: 20
      DBName: !Sub '${Environment}_laravel'
      VPCSecurityGroups:
        - !Ref AppSecurityGroup

Outputs:
  DatabaseEndpoint:
    Description: RDS connection endpoint
    Value: !GetAtt AppDatabase.Endpoint.Address
    Export:
      Name: !Sub '${AWS::StackName}-DBEndpoint'

Common intrinsic functions you will use constantly

CloudFormation intrinsic functions resolve values at deployment time. Master these five first:

  1. !Ref — returns the primary identifier of a resource or parameter value
  2. !GetAtt — retrieves specific attributes from a resource (endpoint URLs, ARNs)
  3. !Sub — substitutes variables into strings using ${Variable} syntax
  4. !ImportValue — references exports from other stacks for cross-stack communication
  5. !If / !Equals — conditional logic for environment-specific configurations

A common mistake I have seen on client projects is hardcoding values that should be parameters or imports. Environment names, instance sizes, CIDR blocks, and database credentials should never be static in production templates. Parameterize early to avoid template duplication later.

How does AWS CloudFormation compare to Terraform for AWS infrastructure?

Choosing between CloudFormation and Terraform depends on your team's constraints, existing tooling, and long-term maintenance strategy. Both accomplish infrastructure as code, but their trade-offs differ significantly.

CriteriaAWS CloudFormationTerraform
AWS IntegrationNative, immediate support for new AWS featuresProvider-dependent, 1-4 week lag for new services
State ManagementAWS-managed, no state file to protectSelf-managed state file (S3 + DynamoDB locking)
Multi-CloudAWS onlyAny provider with a Terraform provider
LanguageYAML or JSON onlyHCL (domain-specific language)
Drift DetectionBuilt-in, scheduled or on-demandRequires terraform plan execution
CostFree (pay only for provisioned resources)Open-source free; Cloud costs extra
Learning CurveModerate, AWS documentation comprehensiveSteeper, HCL syntax plus provider nuances
Module EcosystemAWS-provided modules, smaller communityMassive registry, community modules abundant

For teams operating exclusively on AWS with no multi-cloud roadmap, CloudFormation removes state file management complexity entirely. There is no risk of corrupted state, no S3 bucket permissions to configure, and no DynamoDB table to maintain for locking. When working on serverless Laravel deployments on AWS, CloudFormation integrates natively with SAM and Lambda without additional abstraction layers.

Terraform wins when you need multi-cloud portability, prefer HCL over YAML, or require advanced features like workspace-based environment isolation. However, for Nepal-based teams already standardized on AWS, CloudFormation's zero-overhead state management often outweighs Terraform's flexibility advantages.

Start DecisionMulti-cloud required?YesNoUse TerraformAWS-only project?YesNoUse CloudFormationEvaluate BothZero state managementTeam preference decides
Decision framework for selecting AWS CloudFormation versus Terraform based on multi-cloud needs and AWS exclusivity

How do you manage CloudFormation stacks in production CI/CD pipelines?

Production CloudFormation usage requires disciplined pipeline integration. Manual aws cloudformation deploy commands work for learning but fail at scale. Automate stack operations through CI/CD with proper safeguards.

Change sets before every update

Never apply stack updates directly in production. Always generate a change set first, review it, then execute. This two-phase approach catches unintended deletions, replacements, and configuration changes before they cause outages.

# Generate change set without applying
aws cloudformation create-change-set \
  --stack-name laravel-production \
  --template-body file://infrastructure/app-stack.yaml \
  --parameters ParameterKey=Environment,ParameterValue=production \
               ParameterKey=DBPassword,ParameterValue={{resolve:secretsmanager:prod/db/password}} \
  --change-set-name pre-deploy-review-$(date +%Y%m%d-%H%M%S) \
  --capabilities CAPABILITY_NAMED_IAM

# Review changes
aws cloudformation describe-change-set \
  --stack-name laravel-production \
  --change-set-name pre-deploy-review-20260817-143022

# Execute only after approval
aws cloudformation execute-change-set \
  --stack-name laravel-production \
  --change-set-name pre-deploy-review-20260817-143022

Stack policies to protect critical resources

Stack policies prevent accidental modification or deletion of stateful resources like RDS instances, S3 buckets with data, and Route53 hosted zones. Apply restrictive policies to production stacks immediately after creation.

{
  "Statement": [
    {
      "Effect": "Deny",
      "Action": ["Update:Replace", "Update:Delete"],
      "Principal": "*",
      "Resource": "LogicalResourceId/AppDatabase"
    },
    {
      "Effect": "Allow",
      "Action": "Update:*",
      "Principal": "*",
      "Resource": "*"
    }
  ]
}

This policy allows all updates except replacement or deletion of the AppDatabase resource. Even if a template change would trigger database recreation, CloudFormation rejects the update. For legal-tech portals handling sensitive client data, this safeguard prevents catastrophic data loss during routine deployments.

Integrating with GitLab CI for automated deployments

On projects using Deployer 7 and GitLab CI for application deployments, I integrate CloudFormation into the same pipeline. Infrastructure changes trigger on merge requests to the infrastructure/ directory, separate from application code deployments.

infrastructure_validate:
  stage: validate
  script:
    - aws cloudformation validate-template --template-body file://infrastructure/app-stack.yaml
    - cfn-lint infrastructure/app-stack.yaml
  rules:
    - changes:
        - infrastructure//*

infrastructure_deploy_staging:
  stage: deploy
  needs: [infrastructure_validate]
  script:
    - aws cloudformation deploy
        --stack-name laravel-staging
        --template-file infrastructure/app-stack.yaml
        --parameter-overrides Environment=staging
        --no-fail-on-empty-changeset
        --capabilities CAPABILITY_NAMED_IAM
  environment:
    name: staging
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      changes:
        - infrastructure//*
Code Pushinfrastructure/directory changedValidate Stagevalidate-templatecfn-lintFail fast on errorsCreate Change SetPreview modificationsManual review gateApproval Requiredfor productionExecuteApplyChangesStack Updated
CI/CD pipeline flow for AWS CloudFormation: Infrastructure as Code on AWS with validation, change set preview, approval gate, and execution stages

What are common CloudFormation pitfalls and how do you avoid them?

CloudFormation's declarative model hides complexity that surfaces during failures. Understanding these failure modes prevents production incidents and reduces debugging time.

Handling circular dependencies and resource ordering

CloudFormation automatically determines resource creation order based on references. However, implicit dependencies can create cycles that fail validation. When Resource A references Resource B's output while B also depends on A, CloudFormation cannot determine which to create first.

Solve this by breaking the cycle with explicit DependsOn declarations or restructuring into nested stacks. For VPC architectures where security groups reference each other, create base security groups first, then reference them in subsequent resources rather than creating mutual dependencies.

Managing secrets without exposing them in templates

Never store passwords, API keys, or tokens directly in CloudFormation templates. Use AWS Secrets Manager or SSM Parameter Store with dynamic references:

Resources:
  AppDatabase:
    Type: AWS::RDS::DBInstance
    Properties:
      MasterUserPassword: '{{resolve:secretsmanager:prod/laravel/db-password:SecretString:password}}'

This pattern retrieves the secret at deployment time without embedding it in the template. The resolved value never appears in stack events, change sets, or template artifacts stored in version control. For projects requiring security best practices, this separation is non-negotiable.

Dealing with stack deletion failures

Stack deletions fail when resources cannot be removed automatically. Common causes include non-empty S3 buckets, RDS instances with deletion protection enabled, and ENIs attached to running instances. Before deleting production stacks, verify retention policies and backup requirements.

Set DeletionPolicy: Retain on stateful resources to preserve them during stack deletion. This allows safe stack teardown while keeping databases and storage intact for migration or recovery. Without this policy, a mistaken stack deletion can cause irreversible data loss.

Template size limits and nested stack strategies

CloudFormation templates have a 1 MB size limit (512 KB for direct API calls). Complex architectures exceed this quickly. Split large templates into nested stacks or use modules (available in CloudFormation Registry since 2024).

Nested stacks communicate through parameters and outputs. Keep parent templates focused on orchestration while child templates handle specific concerns (networking, compute, data layer). This modular approach also enables team ownership boundaries where different teams maintain separate stack components.

How do you implement drift detection and ongoing stack governance?

Infrastructure drift occurs when live resources diverge from template definitions due to manual console changes, emergency fixes, or external automation. Undetected drift causes deployment failures and makes templates unreliable as source of truth.

Scheduled drift detection scans

Enable drift detection on production stacks and schedule regular scans. CloudFormation compares actual resource configurations against template definitions and reports discrepancies.

# Initiate drift detection
aws cloudformation detect-stack-drift \
  --stack-name laravel-production

# Check detection status
aws cloudformation describe-stack-drift-detection-status \
  --stack-drift-detection-id abc123-def456

# View drifted resources
aws cloudformation describe-stack-resource-drifts \
  --stack-name laravel-production \
  --stack-resource-drift-status-filter MODIFIED DELETED

Schedule weekly drift scans via EventBridge triggering a Lambda function that reports results to Slack or email. Address drift immediately rather than accumulating technical debt. On legal-tech platforms where compliance requires documented infrastructure states, drift detection provides audit evidence.

Tagging strategy for cost allocation and governance

Implement consistent tagging from day one. Tags enable cost allocation, access control, automation targeting, and compliance reporting. Define a tagging standard covering environment, project, owner, cost center, and data classification.

Use CloudFormation stack-level tags that propagate to all resources automatically. Override individual resource tags only when necessary. Inconsistent tagging creates blind spots in cost analysis and makes automated governance impossible.

Conclusion

AWS CloudFormation: Infrastructure as Code on AWS provides production-grade infrastructure automation for teams committed to the AWS ecosystem. The declarative model, native service integration, and managed state eliminate significant operational complexity compared to external tools. Start with small, focused templates, enforce change sets and stack policies from the beginning, and integrate stack operations into your existing CI/CD workflows rather than treating infrastructure as a separate concern.

For teams evaluating whether to adopt CloudFormation or needing assistance migrating existing manual infrastructure to code, reach out to discuss your specific requirements. Production infrastructure decisions benefit from experienced perspective tailored to your operational constraints and growth trajectory.

Frequently Asked Questions

AWS CloudFormation is a service that provisions and manages AWS infrastructure using JSON or YAML templates. It treats infrastructure as code, enabling version control, repeatability, and automated rollback on failure.

CloudFormation itself is free for standard stacks; you pay only for underlying AWS resources created. Stacks exceeding 1,000 resources incur USD 0.25 per operation, roughly NPR 33 at current exchange rates.

Choose CloudFormation when committed exclusively to AWS and needing native service support without external state files. Prefer Terraform for multi-cloud environments or teams requiring HCL syntax and broader provider ecosystems.

Never hardcode secrets in templates. Use AWS Secrets Manager or SSM Parameter Store references with dynamic resolution. In my experience deploying legal-tech portals, this prevents credential leaks in Git repositories while allowing secure runtime injection during stack creation and updates.

This status indicates resource creation failed and CloudFormation reverted changes. Check the Events tab for specific error messages, often IAM permissions or quota limits. On production deployments I have debugged, missing VPC endpoints or incorrect security group rules frequently trigger rollbacks requiring template correction before updating.

Yes, using change sets to preview modifications before applying them. Some resources like RDS instances require replacement causing brief outages unless configured with Multi-AZ. I always test change sets on staging first, especially for client eCommerce platforms where database connectivity interruptions directly impact revenue during peak Nepali festival seasons.

Use parameter files or nested stacks with environment-specific values passed at deployment time. Avoid duplicating entire templates for dev versus production. On projects I maintain, we store environment parameters in separate JSON files and reference them via CI pipelines, keeping base templates identical across all deployment targets.

Each stack supports maximum 500 resources and template body size of 1MB (S3-hosted up to 460KB). Exceeding these requires splitting into nested stacks or using modules. For complex architectures like multi-vendor marketplaces I have built, modularizing networking, compute, and data layers prevents hitting these constraints during scaling.

Use AWS CodePipeline or GitLab CI to validate templates with cfn-lint, create change sets, and execute deployments automatically. On sister sites sharing deployment infrastructure, our GitLab CI pipeline runs lint checks before calling aws cloudformation deploy, catching syntax errors and policy violations before they reach production environments.

Manual changes cause configuration drift detected during next stack update, potentially triggering unexpected replacements or failures. CloudFormation expects full authoritative control. In practice, I restrict console access for managed resources and document exceptions clearly, treating manual interventions as emergency-only procedures requiring immediate template reconciliation afterward.

Create CloudFormation modules or StackSets for reusable components like VPCs, ECS clusters, or CI runners. Publish validated modules in private Service Catalog portfolios. For Nepal-based agencies managing multiple client accounts, this standardizes baseline security and networking while allowing project-specific customization through well-defined parameter interfaces.

Yes, Lambda-backed custom resources enable provisioning external APIs, DNS records, or third-party integrations within stack lifecycle. Response signals must follow CloudFormation protocol exactly. I have used this pattern integrating eSewa payment webhooks and SMS gateway credentials during stack creation, ensuring dependencies exist before application deployment begins.

Resources may hang waiting for internal signals, health checks, or dependency resolution. Check nested stack events and Lambda logs for custom resources. Increase timeout values cautiously. During one production incident, an ELB target group registration stalled due to misconfigured health check path, resolved only after examining load balancer access logs directly.

Apply least-privilege IAM roles for stack operations, enable termination protection on production stacks, and scan templates with cfn-nag for insecure configurations. Encrypt sensitive parameters and avoid logging outputs containing credentials. On legal platforms handling sensitive documents, we additionally restrict stack modification permissions to senior engineers and audit all change set executions.

Yes, using resource import with DeletionPolicy Retain to bring unmanaged resources under stack control without recreation. Generate accurate templates matching current configuration first. I have migrated legacy client infrastructure this way, importing EC2 instances and RDS databases incrementally while verifying each step to prevent accidental deletion during adoption.

Share this article

Quick Contact Options
Choose how you want to connect me: