From Manual Deployments to Infrastructure-as-Code on AWS
How a 4-person engineering team eliminated deployment risk by migrating from manual AWS console clicks to Terraform + GitHub Actions with zero-downtime releases.
Representative project based on real engagements. Client details anonymized.
The situation
A B2B SaaS company with a 4-person backend team was deploying by clicking through the AWS console. Each release took 2-3 hours: manually pushing Docker images to ECR, updating ECS task definitions, running database migrations by hand, and praying nothing broke. There was no staging environment that matched production. Rollbacks meant re-deploying the previous image manually.
The team shipped once every 2 weeks because deployments were stressful and risky. Features sat in branches for days waiting for a deployment window.
What we built
Terraform modules (week 1-2): We wrote reusable Terraform modules for VPC, ECS Fargate, Aurora PostgreSQL, IAM roles, and CloudWatch alarms. State lives in S3 with DynamoDB locking. Every infrastructure change goes through a pull request with terraform plan output in the PR comment, so the team can review changes before applying.
CI/CD pipeline (week 2-3): GitHub Actions handles the full pipeline: lint → test → build Docker image → push to ECR → deploy to staging → run smoke tests → promote to production. Blue-green deployments on ECS mean the new version runs alongside the old one. If health checks fail, traffic stays on the old version.
Database migrations (week 3): Schema migrations run automatically as part of the deployment pipeline using Prisma Migrate. A pre-deploy step checks for destructive migrations and requires manual approval for anything that drops columns or tables.
Monitoring (week 4): CloudWatch dashboards for ECS service health, Aurora connection pool usage, and API latency. Alarms trigger Slack notifications when error rates spike or latency exceeds thresholds.
The numbers
| Metric | Before | After |
|---|---|---|
| Deploy time | 2-3 hours | 8 minutes |
| Deploy frequency | Every 2 weeks | Multiple times per week |
| Rollback time | 30+ minutes (manual) | 2 minutes (ECS task definition revert) |
| Staging parity | None | Identical to production |
| Deployment risk | High (manual steps) | Low (automated, auditable) |
What we learned
The hardest part was not Terraform or GitHub Actions — it was convincing the team to stop using the AWS console for manual changes. We enforced this with a Terraform drift detection job that runs nightly and alerts if anyone makes manual changes to managed resources. Within 3 weeks, the team stopped clicking around in the console entirely.
Have a similar problem?
Book a short conversation with a senior engineer and we will tell you honestly whether we can help.