Setting Up GitLab CI/CD for Astro Blog Deployment to Cloudflare Pages
Complete guide to automating your Astro blog deployment using GitLab CI/CD pipelines - from zero to production with automated builds, tests, and deployments.
A step-by-step guide to setting up GitLab CI/CD pipelines for your Astro blog, automating the build, test, and deployment process to Cloudflare Pages.
What is GitLab CI/CD?
GitLab CI/CD is a built-in continuous integration and continuous deployment tool that automates your software development workflows. For your Astro blog, it means:
- Automated Builds: Automatically build your blog whenever you push code
- Automated Tests: Run tests to ensure your blog builds correctly
- Automated Deployments: Deploy to Cloudflare Pages automatically
- Pipeline Visualization: See the status of your builds in real-time
- Artifact Storage: Keep build outputs for debugging and rollbacks
Key Components:
| Component | Purpose |
|---|---|
| Pipeline | The complete workflow from code push to deployment |
| Jobs | Individual tasks within a pipeline (build, test, deploy) |
| Stages | Groups of jobs that run in sequence (build → test → deploy) |
| Runners | Servers that execute your jobs |
| Artifacts | Files generated by jobs (built site, test reports) |
| Pipeline Editor | Web IDE for editing .gitlab-ci.yml |
| Pipeline Schedules | Cron-like scheduling for periodic builds |
Why Use GitLab CI/CD for Your Astro Blog?
Benefits for Your Blog:
- Zero Manual Deployment: Push code and forget - deployment happens automatically
- Build Verification: Catch errors before they reach production
- Consistent Builds: Same environment every time, no “works on my machine”
- Fast Rollbacks: Artifacts from previous builds allow quick rollbacks
- Team Collaboration: Multiple authors can contribute without deployment conflicts
- Security: API keys and secrets stored securely in GitLab
Real-World Scenarios:
- Typo Fix: Push a typo fix → Auto-build → Auto-deploy in 2 minutes
- New Post: Add a new blog post → Pipeline runs → Live in minutes
- Dependency Updates: Update Astro version → Pipeline tests it → Safe deployment
- Multiple Environments: Deploy to staging first, then production
When Should You Use GitLab CI/CD?
Perfect For:
Frequent Updates: Publishing blog posts regularly
Multiple Contributors: Team members pushing content
Quality Assurance: Need to verify builds before deployment
Professional Workflow: Want production-grade deployment process
Complex Builds: Using MDX, TypeScript, or custom processing
Scheduled Deployments: Publishing posts at specific times
Not Necessary For:
Static Rarely-Updated Sites: Updating once a month might not justify CI/CD
Solo Developer Learning: Simple FTP upload might be easier when learning
No Build Step: Pure HTML/CSS sites with no build process
How to Set Up GitLab CI/CD
Prerequisites
Before starting, ensure you have:
- Self-hosted GitLab instance with your Astro blog repository
- GitLab Runner configured (shared or project-specific)
- Cloudflare Pages project created
- Cloudflare API token with Pages edit permissions
- Basic understanding of YAML syntax
Architecture Overview
flowchart TD
subgraph Developer["👨💻 Developer Workflow"]
A[Write Blog Post]
B[Git Commit]
C[Git Push]
end
subgraph GitLab["🦊 GitLab CI/CD Pipeline"]
D[Trigger Pipeline]
E[Install Dependencies]
F[Build Astro Site]
G[Run Tests]
H[Create Artifact]
end
subgraph Deployment["☁️ Deployment Decision"]
I{Branch Check}
end
subgraph Staging["📦 Staging"]
J[Deploy to Preview]
L[Preview Environment]
end
subgraph Production["🚀 Production"]
K[Deploy to Production]
M[Live Site]
end
A --> B
B --> C
C --> D
D --> E
E --> F
F --> G
G --> H
H --> I
I -->|feature branch| J
J --> L
I -->|main branch| K
K --> M
style Developer fill:#e1f5ff,stroke:#0288d1,stroke-width:2px
style GitLab fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
style Deployment fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
style Staging fill:#fff9c4,stroke:#f9a825,stroke-width:2px
style Production fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
Step 1: Create GitLab CI/CD Configuration
Create a .gitlab-ci.yml file in the root of your repository:
# .gitlab-ci.yml
# GitLab CI/CD pipeline for Astro blog deployment to Cloudflare Pages
# Define the Docker image to use for all jobs
# Using Node.js 20 as Astro requires Node 18+
image: node:20
# Define pipeline stages (run in order)
stages:
- install # Install dependencies
- build # Build the Astro site
- test # Run tests
- deploy # Deploy to Cloudflare Pages
# Cache node_modules between pipeline runs
# This speeds up subsequent builds
cache:
key:
files:
- package-lock.json # Cache invalidates when package-lock.json changes
paths:
- node_modules/
- .npm/
# Global variables available to all jobs
variables:
npm_config_cache: '$CI_PROJECT_DIR/.npm'
# ==========================================
# STAGE 1: Install Dependencies
# ==========================================
install_dependencies:
stage: install
script:
- echo "Installing dependencies..."
- npm ci --prefer-offline --no-audit
artifacts:
expire_in: 1 hour
paths:
- node_modules/
only:
- branches # Run on all branches
# ==========================================
# STAGE 2: Build Astro Site
# ==========================================
build_site:
stage: build
dependencies:
- install_dependencies
script:
- echo "Building Astro site..."
- npm run build
- echo "Build completed successfully!"
- ls -lah dist/
artifacts:
expire_in: 1 week
paths:
- dist/ # Built site
- package.json # Needed for deployment
only:
- branches
# ==========================================
# STAGE 3: Test (Optional but Recommended)
# ==========================================
test_build:
stage: test
dependencies:
- build_site
script:
- echo "Running build verification tests..."
# Check if dist directory exists and has content
- test -d dist || (echo "dist directory not found!" && exit 1)
- test -f dist/index.html || (echo "index.html not found!" && exit 1)
# Check for required files
- test -d dist/_astro || (echo "Assets directory missing!" && exit 1)
- echo "Build verification passed!"
only:
- branches
# ==========================================
# STAGE 4: Deploy to Cloudflare Pages
# ==========================================
# Deploy to staging (feature branches)
deploy_staging:
stage: deploy
dependencies:
- build_site
before_script:
- npm install -g wrangler
script:
- echo "Deploying to Cloudflare Pages (Staging)..."
- |
wrangler pages deploy dist \
--project-name=blog-stack101 \
--branch=$CI_COMMIT_REF_NAME \
--commit-hash=$CI_COMMIT_SHORT_SHA \
--commit-message="$CI_COMMIT_MESSAGE"
- echo "Staging deployment complete!"
- echo "Preview URL will be displayed above ⬆️"
environment:
name: staging/$CI_COMMIT_REF_NAME
url: https://$CI_COMMIT_REF_SLUG.blog-stack101.pages.dev
only:
- branches
except:
- main # Don't deploy staging for main branch
# Deploy to production (main branch only)
deploy_production:
stage: deploy
dependencies:
- build_site
before_script:
- npm install -g wrangler
script:
- echo "Deploying to Cloudflare Pages (Production)..."
- |
wrangler pages deploy dist \
--project-name=blog-stack101 \
--branch=main \
--commit-hash=$CI_COMMIT_SHORT_SHA \
--commit-message="$CI_COMMIT_MESSAGE"
- echo "Production deployment complete!"
- echo "Site is live at https://blog.stack101.dev 🚀"
environment:
name: production
url: https://blog.stack101.dev
only:
- main # Only deploy to production from main branch
when: manual # Require manual approval for production deploymentsStep 2: Configure GitLab CI/CD Variables
Store sensitive credentials securely in GitLab:
Navigate to Settings:
- Go to your GitLab project
- Click Settings → CI/CD
- Expand Variables section
- Click Add Variable
Add Cloudflare Credentials:
| Variable Name | Value | Protected | Masked | Description |
|---|---|---|---|---|
CLOUDFLARE_API_TOKEN | Your API token | ✅ Yes | ✅ Yes | Cloudflare API token with Pages edit permissions |
CLOUDFLARE_ACCOUNT_ID | Your account ID | ✅ Yes | ❌ No | Found in Cloudflare dashboard URL |
How to Get Cloudflare API Token:
- Go to Cloudflare Dashboard
- Click My Profile → API Tokens
- Click Create Token
- Use template: Edit Cloudflare Workers
- Or create custom token with permissions:
- Account - Cloudflare Pages: Edit
- Copy the token immediately (shown only once)
- Add it to GitLab CI/CD variables
Step 3: Configure GitLab Runner
Option A: Use Shared Runners (Easier)
If your GitLab instance has shared runners enabled:
- Go to Settings → CI/CD → Runners
- Enable Shared runners for this project
- No additional configuration needed
Option B: Set Up Project Runner (More Control)
If you need a dedicated runner:
# On your GitLab Runner server (can be same as GitLab host)
# Install GitLab Runner
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install gitlab-runner
# Register the runner
sudo gitlab-runner register
# Follow the prompts:
# GitLab instance URL: https://your-gitlab.com
# Registration token: (from Settings → CI/CD → Runners)
# Description: blog-stack101-runner
# Tags: docker,astro,nodejs
# Executor: docker
# Default Docker image: node:20Step 4: Create wrangler.toml Configuration
Create wrangler.toml in your project root:
# wrangler.toml
# Cloudflare Pages configuration
name = "blog-stack101"
compatibility_date = "2024-12-06"
# Pages-specific configuration
pages_build_output_dir = "dist"
# Environment variables (non-sensitive)
[env.production]
NODE_VERSION = "20"
[env.preview]
NODE_VERSION = "20"Step 5: Test Your Pipeline
First Pipeline Run:
Commit and push your changes:
git add .gitlab-ci.yml wrangler.toml git commit -m "feat: add GitLab CI/CD pipeline for automated deployment" git push origin feature/ci-cdWatch the pipeline:
- Go to CI/CD → Pipelines in GitLab
- Click on the running pipeline
- Watch each job execute in real-time
Check the results:
- ✅ Green checkmarks = Success
- ❌ Red X = Failed (click to see logs)
- 🔵 Blue circle = Running
- ⏸️ Gray = Manual action required
Expected Pipeline Flow:
┌─────────────────┐
│ install_deps │ ~30s ✅
└────────┬────────┘
│
┌────────▼────────┐
│ build_site │ ~45s ✅
└────────┬────────┘
│
┌────────▼────────┐
│ test_build │ ~10s ✅
└────────┬────────┘
│
┌────────▼────────┐
│ deploy_staging │ ~20s ✅
└─────────────────┘
Preview: https://feature-ci-cd.blog-stack101.pages.devStep 6: Configure Pipeline Schedules (Optional)
Automatically rebuild your blog at specific times:
Use Case: Scheduled Posts
If you write posts with future publish dates, schedule nightly builds:
- Go to CI/CD → Schedules
- Click New schedule
- Configure:
- Description:
Nightly rebuild for scheduled posts - Interval pattern:
0 2 * * *(2 AM daily) - Cron timezone: Your timezone
- Target branch:
main - Variables: (none needed)
- Description:
- Click Save pipeline schedule
Common Cron Patterns:
| Pattern | Description |
|---|---|
0 2 * * * | Daily at 2:00 AM |
0 */6 * * * | Every 6 hours |
0 0 * * 0 | Weekly on Sunday at midnight |
0 9 * * 1-5 | Weekdays at 9:00 AM |
Step 7: Understanding Pipeline Artifacts
What Are Artifacts?
Artifacts are files generated by your pipeline jobs that are preserved for later use:
- Build artifacts: The
dist/folder containing your built site - Test reports: Results from automated tests
- Logs: Build and deployment logs
Accessing Artifacts:
- Go to CI/CD → Pipelines
- Click on a successful pipeline
- Click the Download icon next to jobs
- Select artifacts to download
Artifact Benefits:
- Debugging: Download and inspect failed builds
- Rollbacks: Redeploy previous artifacts
- Auditing: Keep history of what was deployed when
- Testing: Download and test builds locally
Advanced Configuration
Parallel Jobs for Faster Builds
Speed up your pipeline by running tests in parallel:
# Run multiple test jobs simultaneously
test_links:
stage: test
script:
- npm run test:links # Check for broken links
test_a11y:
stage: test
script:
- npm run test:accessibility # Accessibility tests
test_performance:
stage: test
script:
- npm run test:lighthouse # Lighthouse performance testsConditional Deployments
Deploy only when specific files change:
deploy_production:
stage: deploy
script:
- wrangler pages deploy dist --project-name=blog-stack101
only:
refs:
- main
changes:
- src/**/*
- public/**/*
- package.json
- astro.config.mjsNotification Integration
Get notified when pipelines fail:
# Add to .gitlab-ci.yml
notify_failure:
stage: .post # Runs after all other stages
script:
- |
curl -X POST https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/sendMessage \
-d chat_id=$TELEGRAM_CHAT_ID \
-d text="🚨 Pipeline failed for $CI_PROJECT_NAME"
when: on_failure # Only run when pipeline fails
only:
- mainTroubleshooting Common Issues
Issue 1: Pipeline Fails at Build Stage
Error: npm ERR! missing script: build
Solution:
# Verify package.json has build script
cat package.json | grep -A 5 "scripts"
# Should contain:
# "scripts": {
# "build": "astro build"
# }Issue 2: Cloudflare Deployment Fails
Error: Error: Authentication error
Solution:
- Check
CLOUDFLARE_API_TOKENis set correctly - Verify token has Pages edit permissions
- Ensure token hasn’t expired
Issue 3: Out of CI/CD Minutes
Error: Quota exceeded for runner
Solution:
- Check Settings → Usage Quotas
- Optimize cache to reduce build times
- Consider self-hosted runner for unlimited minutes
Issue 4: Slow Builds
Symptoms: Builds taking >5 minutes
Solutions:
# Add cache for faster installs
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- .npm/
# Use npm ci instead of npm install
script:
- npm ci --prefer-offline --no-auditBest Practices
1. Use Branch Protection
Require CI/CD to pass before merging:
- Go to Settings → Repository → Branch protection
- Add rule for
mainbranch:- ✅ Require approval from code owners
- ✅ Require pipelines to succeed
- ✅ Prevent force push
2. Tag Production Releases
Create git tags for production deployments:
# After successful deployment
git tag -a v1.0.0 -m "Release v1.0.0 - Added CI/CD pipeline"
git push origin v1.0.03. Monitor Pipeline Performance
Track metrics in Analytics → CI/CD Analytics:
- Pipeline success rate
- Average pipeline duration
- Most failing jobs
4. Use Pipeline Templates
Create reusable templates for common jobs:
# .gitlab/ci/templates/deploy.yml
.deploy_template:
before_script:
- npm install -g wrangler
script:
- wrangler pages deploy dist --project-name=$PROJECT_NAME
# Use in main .gitlab-ci.yml
include:
- local: '.gitlab/ci/templates/deploy.yml'
deploy_prod:
extends: .deploy_template
variables:
PROJECT_NAME: blog-stack101Pipeline Workflow Example
Feature Development Workflow:
# 1. Create feature branch
git checkout -b feature/new-blog-post
# 2. Write your blog post
# Edit src/content/blog/my-new-post.mdx
# 3. Commit and push
git add .
git commit -m "feat: add new blog post about GitLab CI/CD"
git push origin feature/new-blog-post
# 4. Pipeline automatically:
# ✅ Installs dependencies
# ✅ Builds site
# ✅ Runs tests
# ✅ Deploys to staging preview
# 📧 Sends you preview URL
# 5. Review preview:
# https://feature-new-blog-post.blog-stack101.pages.dev
# 6. Create merge request
# GitLab → Merge Requests → New merge request
# 7. After approval and merge to main:
# ✅ Pipeline runs again on main branch
# ⏸️ Waits for manual approval
# ✅ Click "Deploy to Production"
# 🚀 Live at https://blog.stack101.devMonitoring and Maintenance
Weekly Checklist:
- Review failed pipelines and fix recurring issues
- Check CI/CD usage quota (Settings → Usage Quotas)
- Update dependencies if security alerts appear
- Review artifact storage and clean up old artifacts
Monthly Tasks:
- Update GitLab Runner to latest version
- Review and optimize cache configuration
- Check Cloudflare API token expiration
- Update Node.js version in pipeline if needed
Cost Considerations
GitLab CI/CD Costs (Free Tier):
- 400 minutes/month free CI/CD minutes
- 10 GB artifact storage
- 5 concurrent jobs
Your Blog’s Usage:
Typical pipeline: ~2 minutes per run
- 10 posts/month: ~20 minutes (5% of quota)
- 50 posts/month: ~100 minutes (25% of quota)
- Daily rebuilds: ~60 minutes (15% of quota)
Total estimated usage: 40% of free quota = $0/month
If You Exceed Free Tier:
Option 1: Self-hosted runner (unlimited minutes, $0) Option 2: GitLab Premium ($29/user/month, 10,000 minutes) Option 3: Optimize pipeline to use fewer minutes
Conclusion
You now have a production-ready CI/CD pipeline for your Astro blog that:
- ✅ Automatically builds on every commit
- ✅ Runs tests to catch errors early
- ✅ Deploys preview environments for feature branches
- ✅ Requires manual approval for production deployments
- ✅ Stores build artifacts for debugging and rollbacks
- ✅ Provides full deployment history and audit trail
This setup gives you the confidence to publish content knowing that every deployment has been tested and validated automatically.
Next Steps
Consider enhancing your pipeline with:
- Automated Testing: Add link checking, accessibility tests, performance tests
- SEO Validation: Verify meta tags and sitemaps before deployment
- Image Optimization: Compress images automatically during build
- Content Validation: Check for spelling, grammar, and broken links
- Analytics Integration: Track deployment success rates and performance
Resources
Share this post
Found this helpful? Share it with your network!
