CI/CD Deployment
On this page, you will:
- Create a GitHub Actions workflow for deploying Prefect flows
- Configure environment variables from AWS Secrets Manager
- Understand environment-specific deployment overrides
- Set up automated deployment on push to main
Overview
With flows built and tested locally, you need a way to deploy them automatically when code merges to main. This page sets up a GitHub Actions workflow that runs prefect deploy --all whenever flow code changes.
┌─────────────────────────────────────────────────────────────────────────────┐
│ CI/CD FLOW DEPLOYMENT │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
│ │ Push to main │ │ GitHub Actions │ │ Prefect Cloud │ │
│ │ │ ────▶ │ │ ────▶ │ │ │
│ │ (flows/ or │ │ uv sync │ │ Deployments │ │
│ │ prefect.yaml) │ │ prefect deploy │ │ updated │ │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ AWS Secrets Mgr │ │
│ │ prefect/api-key │ │
│ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Prerequisites
Ensure you have completed:
- Prefect Cloud Setup — Work pools and API key in Secrets Manager
- Your First Flow — At least one flow deployed
- GitHub OIDC configured for AWS access (from AWS Terraform Setup)
Why Automate Deployment?
Without CI/CD, deploying flows requires a developer to run prefect deploy --all from their local machine. This creates several problems:
- Deployments can drift from
mainif someone forgets to deploy after merging - Local environment differences may produce different deployment configurations
- No audit trail of who deployed what and when
- Blocked if the developer who usually deploys is unavailable
Automating deployment ensures every merge to main immediately updates Prefect Cloud with the latest flow definitions, schedules, and configuration.
GitHub Actions Workflow
Add Repository Secrets
The workflow needs the Prefect API URL to authenticate with Prefect Cloud. In your GitHub repository settings (Settings > Secrets and variables > Actions), add:
| Type | Name | Value |
|---|---|---|
| Variable | TERRAFORM_ROLE_ARN |
Your TerraformGitHubActionsRole ARN |
| Secret | PREFECT_API_URL |
https://api.prefect.cloud/api/accounts/{ACCOUNT_ID}/workspaces/{WORKSPACE_ID} |
The Prefect API key is fetched from AWS Secrets Manager at runtime (not stored as a GitHub secret), so it can be rotated without updating GitHub.
Create the Workflow
Create .github/workflows/prefect-deploy.yml in your data-pipelines repository:
name: Deploy Prefect Flows
on:
push:
branches: [main]
paths:
- 'flows/**'
- 'pipelines/**'
- 'sources/**'
- 'utils/**'
- 'prefect.yaml'
workflow_dispatch: # Allow manual trigger
env:
AWS_REGION: eu-west-2
PYTHON_VERSION: "3.12"
jobs:
deploy:
name: Deploy Flows
runs-on: ubuntu-latest
permissions:
id-token: write # OIDC authentication
contents: read
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ vars.TERRAFORM_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: Get Prefect API key from Secrets Manager
uses: aws-actions/aws-secretsmanager-get-secrets@v2
with:
secret-ids: |
PREFECT_API_KEY, prefect/api-key
parse-json-secrets: false
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python
run: uv python install ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: uv sync
- name: Add venv to PATH
run: echo "$GITHUB_WORKSPACE/.venv/bin" >> $GITHUB_PATH
- name: Deploy all flows
env:
PREFECT_API_URL: ${{ secrets.PREFECT_API_URL }}
run: prefect deploy --all
To deploy manually from your local machine:
cd ~/projects/data/data-pipelines
# Ensure you're authenticated
prefect cloud login
# Deploy all flows
prefect deploy --all
Or deploy a specific flow:
prefect deploy --name exchange-rates-daily
How It Works
- Trigger: The workflow runs when files in
flows/,pipelines/,sources/,utils/, orprefect.yamlchange onmain - AWS Authentication: Uses OIDC to assume the Terraform GitHub Actions role (no long-lived credentials)
- Prefect API Key: Fetched from AWS Secrets Manager using the
aws-secretsmanager-get-secretsaction, automatically masked in logs - Dependencies: Installed via
uv syncfrompyproject.tomlanduv.lock - Deployment:
prefect deploy --allreadsprefect.yamland creates/updates all deployments in Prefect Cloud
The workflow_dispatch trigger also allows manual deployment from the GitHub Actions UI, useful for re-deploying after a Prefect Cloud configuration change.
Environment-Specific Overrides
If you need different configurations per environment (e.g., different work pools for staging vs production), use Prefect's variable substitution in prefect.yaml:
deployments:
- name: exchange-rates-daily
entrypoint: flows/exchange_rates.py:exchange_rates_daily_flow
work_pool:
name: "{{ $PREFECT_WORK_POOL | default('production') }}"
schedules:
- cron: "0 9 * * *"
timezone: "UTC"
active: true
Then set the environment variable in the workflow:
- name: Deploy all flows
env:
PREFECT_API_KEY: ${{ steps.prefect-key.outputs.key }}
PREFECT_API_URL: ${{ secrets.PREFECT_API_URL }}
PREFECT_WORK_POOL: production
run: prefect deploy --all
This allows the same prefect.yaml to target different work pools depending on the deployment context.
API Key Rotation
Because the Prefect API key lives in AWS Secrets Manager (not as a GitHub secret), rotating it requires a single command:
aws secretsmanager put-secret-value \
--secret-id "prefect/api-key" \
--secret-string "NEW_API_KEY_HERE" \
--profile infrastructure-admin
The next workflow run automatically picks up the new key. No GitHub repository settings need to change.
Troubleshooting
Workflow Fails at "Fetch Prefect API key"
An error occurred (AccessDeniedException) when calling the GetSecretValue operation
Solution: The GitHub Actions IAM role needs secretsmanager:GetSecretValue permission for prefect/* secrets. Check the IAM policy in terraform/aws/oidc.tf includes the prefect/* prefix (configured in Prefect Cloud Setup).
Deployment Succeeds but Flows Don't Run
Solution: Check the work pool name in prefect.yaml matches an existing work pool, and that a worker is connected to that pool:
prefect work-pool ls
prefect worker ls --pool production
"No module named" Errors
Solution: Ensure all dependencies are in pyproject.toml and the uv sync step succeeds. Check the workflow logs for installation errors.
Summary
You've set up automated flow deployment:
- Created a GitHub Actions workflow triggered on push to
main - Configured AWS OIDC authentication for Secrets Manager access
- Fetched the Prefect API key securely at runtime
- Deployed flows using
prefect deploy --all
What's Next
With CI/CD deployment in place, set up alerting to know when flows fail.
Continue to Alerting and Notifications →