Goodbye Manual Deployments: How GitHub Actions Made AWS CI/CD Effortless ✨🚀
Photo by Ulysse Pointcheval on Unsplash
Every time I updated my AWS project manually, it felt like walking a tightrope 🎪 — small mistakes or missed steps would often lead to frustrating manual fixes and wasted time.
For context, I was maintaining a personal Single Page Application (SPA) hosted on AWS — a passion project that started to feel more like a tedious chore to deploy manually.
I knew there had to be a better way.
This is the story of how I finally embraced GitHub Actions and moved from chaotic manual deployments to smooth, automated CI/CD workflows — and why I wish I’d done it sooner.
The Struggles of Manual Deployments 😩
For a long time, deployment was a stressful checklist:
- Build locally 🛠️
- Upload to S3 Bucket 🪣️
- Invalidate CloudFront cache ☁️
- Pray nothing breaks 🙏
Every change, no matter how small, meant repeating the entire cycle.
Sometimes I’d forget a step. Sometimes the browser cache would refuse to refresh. Sometimes a deployment would quietly fail without me noticing.
One time, I accidentally uploaded an outdated static folder because I forgot to rebuild the assets. ⚠️
The result? A half-broken site that visitors started noticing.
It took me another two hours to manually diagnose and fix the issue — time I could have spent building new features.
Clearly, this wasn’t scalable.
Discovering GitHub Actions 🔍
I had heard of GitHub Actions before but assumed it would be complicated to set up.
Spoiler: It wasn’t.
After a few experiments (and a lot of trial and error) 🔄, I realized how powerful it could be for my needs.
Automating AWS deployments suddenly became not only possible — but surprisingly elegant.
And the more I automated, the more I realized:
Automation isn’t just about saving time — it’s about reducing cognitive load. 🧠
No more wondering “Did I forget to invalidate CloudFront?” or “Was that the latest version I uploaded?”.
Building the CI/CD Workflow 🛠️⚙️
I wanted a workflow that would:
- Detect a
pushto themainbranch. ✅ - Build the latest React app 🔥
- Sync updated files to an S3 bucket. ☁️
- Invalidate CloudFront cache automatically. 🔄
- Update the prod Git tag to reflect the deployed commit. 🏷️
Here’s the heart of my GitHub Actions workflow:
name: Deploy to AWS
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '23.5.0'
- name: Cache node_modules
uses: actions/cache@v3
with:
path: ~/.npm
key: $-node-$
restore-keys: |
$-node-
- name: Install Dependencies
run: npm install
- name: Build React App
run: |
NODE_ENV=production npm run build
- name: Verify Build Output
run: test -d build && echo "✅ Build exists"
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: $
aws-secret-access-key: $
aws-region: ap-southeast-1
- name: Sync files to S3
run: aws s3 sync ./build s3://your-bucket-name/ --delete
- name: Invalidate CloudFront cache
run: |
aws cloudfront create-invalidation --distribution-id ABC123XYZ --paths "/*"
- name: Update `prod` tag to current commit
run: |
git config user.name "github-actions"
git config user.email "github-actions@github.com"
git tag -f prod
git push origin prod --force
A quick breakdown:
- Checkout code : Grabs the latest code from GitHub. 📦
- Setup Node.js : Installs Node.js for building the app. 🔧
- Cache node_modules : Speeds up future builds by reusing dependencies. ⚡
- Install dependencies : Installs all required packages. 📦
- Build React App : Compiles the production build. 🏗️
- Verify build output : Ensures the build/ directory was created successfully. ✅
- Configure AWS credentials : Authenticates the workflow securely. 🔐
- Sync to S3 : Uploads the build/ directory to S3. ☁️
- CloudFront invalidation : Forces the cache to refresh after deployment. 🔄
- Update prod Git tag : Tags the deployed commit for easy production tracking. 🏷️
Lessons Learned Along the Way ✏️
Setting up CI/CD wasn’t without its lessons:
- Secrets management matters : Store AWS credentials securely using GitHub Secrets. 🔒
- Test small first : Start by automating just the S3 sync before adding cache invalidation. 🧪
- Expect iteration : My first few pipeline runs weren’t perfect. That’s normal. 🔄
Pro tip if you’re starting out :
Don’t overcomplicate your first pipeline. Start with just one automated task — even if it’s just syncing files to S3. Once you see it work, adding more steps becomes almost addictive. ✨
What I’d Improve Next 🛠️➡️
Now that basic CI/CD is in place, I’m thinking about what’s next:
- Add a notification (via Slack or email) when a deployment succeeds or fails. 🔔
- Introduce a basic build/test stage before deployment to catch issues earlier. 🧪
- Explore using GitHub Environments for even safer staging and production pipelines. 🛡️
Automation isn’t a one-time task — it’s a journey. 🛤️
And every small improvement compounds over time.
Final Thoughts 💬
If you’re still stuck in the cycle of manual deployments and wondering if automation is worth the effort — trust me, it is.
The time and peace of mind you gain are priceless.
GitHub Actions turned deployment from a tedious task into something almost… magical. ✨
Have you automated your deployments yet? 🚀
I’d love to hear your stories, struggles, or favorite CI/CD tricks.
Drop a comment below, highlight your favorite parts, and if you found this post helpful, don’t forget to hit the clap button! 👏
Let’s make deployment painless — together. 🤝