npx skills add ...
npx skills add astronomer/agents --skill creating-openlineage-extractors
Create custom OpenLineage extractors for Airflow operators. Use when the user needs lineage from unsupported or third-party operators, wants column-level lineage, or needs complex extraction logic beyond what inlets/outlets provide.
npx skills add astronomer/agents --skill creating-openlineage-extractors
This skill guides you through creating custom OpenLineage extractors to capture lineage from Airflow operators that don't have built-in support.
Reference: See the OpenLineage provider developer guide for the latest patterns and list of supported operators/hooks.
| Scenario | Approach |
|---|---|
| Operator you own/maintain | OpenLineage Methods (recommended, simplest) |
| Third-party operator you can't modify | Custom Extractor |
| Need column-level lineage | OpenLineage Methods or Custom Extractor |
| Complex extraction logic | OpenLineage Methods or Custom Extractor |
| Simple table-level lineage | Inlets/Outlets (simplest, but lowest priority) |
Important: Always prefer OpenLineage methods over custom extractors when possible. Extractors are harder to write, easier to diverge from operator behavior after changes, and harder to debug.
Astro includes built-in OpenLineage integration — no additional transport configuration is needed. Lineage events are automatically collected and displayed in the Astro UI's Lineage tab. Custom extractors deployed to an Astro project are automatically picked up, so you only need to register them in airflow.cfg or via environment variable and deploy.
Use when you can add methods directly to your custom operator. This is the go-to solution for operators you own.
Use when you need lineage from third-party or provider operators that you cannot modify.
When you own the operator, add OpenLineage methods directly:
| Method | When Called | Required |
|---|---|---|
get_openlineage_facets_on_start() | Task enters RUNNING | No |
get_openlineage_facets_on_complete(ti) | Task succeeds | No |
get_openlineage_facets_on_failure(ti) | Task fails | No |
Implement only the methods you need. Unimplemented methods fall through to Hook-Level Lineage or inlets/outlets.
Use this approach only when you cannot modify the operator (e.g., third-party or provider operators).
| Method | When Called | Use For |
|---|---|---|
_execute_extraction() | Before operator runs | Static/known lineage |
extract_on_complete(task_instance) | After success | Runtime-determined lineage |
extract_on_failure(task_instance) | After failure | Partial lineage on errors |
Option 1: Configuration file (airflow.cfg)
Option 2: Environment variable
Important: The path must be importable from the Airflow worker. Place extractors in your DAGs folder or installed package.
Problem: Importing Airflow modules at the top level causes circular imports.
Problem: Extractor path doesn't match actual module location.
Problem: Extraction fails when operator properties are None.
OpenLineage checks for lineage in this order:
HookLineageCollector)If a custom extractor exists, it overrides built-in extraction and inlets/outlets.