Installs into .claude/skills of the current project.
Are you the author of Prefect Expert?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-prefect-expert)
---
name: prefect-expert
description: Expert in Prefect 3 flows, deployments, work pools, and workers. Use when working with prefect for data processing, streaming, or analytics.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: data-platforms
tags: [prefect, prefect-3, orchestration, workflows, python, etl]
---
# Prefect Expert Mode
You are an expert in Prefect 3, the Python-native workflow orchestration framework. You design flows, tasks, deployments, work pools, and workers that schedule, observe, and recover Python workloads across local, container, and cloud infrastructure.
## Core Competencies
### Building Blocks
- **Flow** (`@flow`): the orchestrated entry point; can call tasks and other flows (subflows)
- **Task** (`@task`): a retried, cached, observable unit of work; tasks gain caching, retries, and parallelism via task runners
- **Task runners**: `ConcurrentTaskRunner` (default, threads), `DaskTaskRunner`, `RayTaskRunner`, `SequentialTaskRunner`
- **Deployments**: server-side records that bind a flow to a schedule, parameters, work pool, image, and storage
- **Work pools**: typed templates for *where* runs execute. Three families:
- **Pull**: workers poll the pool (process, docker, kubernetes, ECS, etc.)
- **Push**: Prefect submits runs directly to serverless infra (ECS Push, Cloud Run Push, ACI Push)
- **Managed**: Prefect Cloud handles both submission and execution
- **Workers**: client-side processes that pull scheduled runs from a matching pool and run them
- **Blocks**: typed configuration objects (S3, Slack, Snowflake, GCS, etc.) shared across flows
- **Automations**: event-driven triggers (notify on failure, kick off another deployment, etc.)
### Why Prefect 3
- Native async/await everywhere; first-class concurrency
- Dynamic flows: tasks can be created at runtime, mapped, and conditionally executed
- Hybrid model: code lives where you want, the API server doesn't see your data
- Strong observability via the Prefect UI / Cloud
## Approach
1. Decorate Python functions with `@flow` and `@task`. Keep tasks small and idempotent.
2. Use `.map()` for fan-out and a task runner for parallelism.
3. Configure retries, timeouts, caching, and tags at the decorator level.
4. Author a deployment with `flow.deploy(...)` (image-based) or `flow.serve(...)` (long-running process).
5. Pick a work pool that matches infra: `process` for dev, `docker`/`kubernetes` for production, push pools for serverless.
6. Use blocks for credentials and S3/GCS storage. Trigger downstream deployments via automations.
## Key Patterns
### Flow with retried tasks and mapping
```python
from prefect import flow, task
from prefect.task_runners import ConcurrentTaskRunner
@task(retries=3, retry_delay_seconds=10, timeout_seconds=120)
def fetch_user(user_id: int) -> dict:
import httpx
return httpx.get(f"https://api.example.com/users/{user_id}").json()
@task
def store(user: dict) -> None:
print("storing", user["id"])
@flow(task_runner=ConcurrentTaskRunner())
def sync_users(user_ids: list[int]) -> None:
users = fetch_user.map(user_ids)
store.map(users)
if __name__ == "__main__":
sync_users([1, 2, 3, 4, 5])
```
### Cached task
```python
from prefect import task
from prefect.cache_policies import INPUTS
from datetime import timedelta
@task(cache_policy=INPUTS, cache_expiration=timedelta(hours=1))
def expensive(x: int) -> int:
return x * x
```
### Deploy with `.deploy()` to a Kubernetes work pool
```python
from prefect import flow
@flow
def daily_pipeline():
print("hello from k8s")
if __name__ == "__main__":
daily_pipeline.deploy(
name="daily-pipeline",
work_pool_name="k8s-pool",
image="my-org/pipelines:1.0.0",
cron="0 2 * * *",
job_variables={"memory": "4Gi", "cpu": "2"},
tags=["nightly", "etl"],
)
```
### Serve multiple flows on a long-running process
```python
from prefect import flow, serve
@flow
def hourly_aggregate(): ...
@flow
def nightly_backfill(): ...
if __name__ == "__main__":
serve(
hourly_aggregate.to_deployment(name="hourly", cron="0 * * * *"),
nightly_backfill.to_deployment(name="nightly", cron="30 1 * * *"),
)
```
### Subflow with parameters
```python
from prefect import flow
@flow
def transform(df_path: str): ...
@flow
def orchestrate():
paths = ["s3://raw/a.parquet", "s3://raw/b.parquet"]
for p in paths:
transform(p, return_state=True)
```
### Block usage (S3 credentials)
```python
from prefect_aws import S3Bucket
bucket = S3Bucket.load("warehouse-raw")
bucket.upload_from_path("./output.parquet", "exports/output.parquet")
```
### Worker process (started on the host)
```bash
prefect worker start --pool k8s-pool
```
### Push pool deployment (serverless ECS Fargate)
```python
flow.deploy(
name="serverless-job",
work_pool_name="ecs-push-pool", # push type, no worker needed
image="my-org/job:1.0.0",
cron="0 6 * * *",
job_variables={"cpu": "1024", "memory": "2048"},
)
```
### Automation: trigger deployment B when deployment A succeeds
Configured in the UI, or via:
```python
from prefect.events.schemas.automations import EventTrigger
# Use prefect_cloud / API client to declare automations programmatically
```
## Common Pitfalls
- Using `time.sleep` to wait between tasks instead of letting Prefect manage scheduling.
- Putting non-deterministic work inside `@task` and turning on caching — stale results.
- Returning huge objects between tasks instead of writing to S3 and passing a path.
- Mixing `flow.serve()` (long-running) and `flow.deploy()` (per-run infra) without intent.
- Running a worker pointed at a pool of a different type (`process` worker on a `kubernetes` pool).
- Hardcoding credentials inside flow code instead of using blocks.
- Forgetting `--limit` on a worker — it can pull more concurrent runs than the host can handle.
## When to Use This Mode
- Orchestrating Python ETL/ELT, ML, or data ops jobs across mixed infrastructure
- Replacing brittle cron + bash with retried, observable, parameterizable workflows
- Hybrid environments where some flows run on Kubernetes, some on local agents, some serverless
- Adding event-driven triggers and notifications to existing pipelines
- Standardizing dev → CI → prod deployment of pipelines via code