etl-design
Skill1 starsChanged 7 months agoMITView on GitHub
Design ETL/ELT workflows: source extraction, transformation logic, incremental loading, schema evolution, and orchestration. Use when planning how data moves from source systems to the warehouse, designing transformation logic, implementing incremental or full-refresh loading strategies, or handling schema changes. Trigger phrases: "design an ETL", "ELT workflow", "data transformation design", "incremental loading strategy", "schema evolution", "dbt model design", "transformation logic", "staging to production", "data loading strategy", "source to warehouse", "ETL architecture", "ELT pipeline design"
- Deletes or force-pushes
In this repository164 other files it gives its agents.
- instrument-data-to-allotropeSkill
- literature-reviewSkill
- nextflow-developmentSkill
- scientific-problem-selectionSkill
- scvi-toolsSkill
- single-cell-rna-qcSkill
- discover-brandSkill
- enforce-voiceSkill
- generate-guidelinesSkill
- csat-reportSkill
- customer-escalationSkill
- customer-researchSkill
- draft-responseSkill
- kb-articleSkill
- sentiment-analysisSkill
- ticket-triageSkill
- analyzeSkill
- build-dashboardSkill
- create-vizSkill
- data-context-extractorSkill
- data-modelingSkill
- data-pipelineSkill
- explore-dataSkill
- sql-queriesSkill
- statistical-analysisSkill
- validate-dataSkill
- write-querySkill
- accessibility-reviewSkill
- component-librarySkill
- design-critiqueSkill
- design-handoffSkill
- design-systemSkill
- frontend-designSkill
- research-synthesisSkill
- user-researchSkill
- ux-copySkill
- wireframingSkill
- Agent DevelopmentSkill
- CLAUDE.md ManagementSkill
- MCP Server BuilderSkill
- Plugin DevelopmentSkill
- Prompt EngineeringSkill
- Skill CreatorSkill
- curriculum-designSkill
- lesson-planningSkill
- quiz-generatorSkill
- study-guideSkill
- tutoringSkill
- api-designSkill
- architectureSkill
- ci-cd-pipelineSkill
- code-reviewSkill
- database-migrationSkill
- debugSkill
- dependency-auditSkill
- deploy-checklistSkill
- documentationSkill
- error-handlingSkill
- git-workflowSkill
- incident-responseSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 7 are distinctive, and 0 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈7
Distinctive · estimate
This author's own choices. Worth a look.
0
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 29
Recommendation: Use ELT for most modern data warehouse projects.
- Distinctive: line 79
Use a layered transformation architecture:
- Distinctive: line 257
Use sensors or triggers for event-driven starts
- Distinctive: line 284
Land raw data first: Always store the unmodified source data before transforming.
- Distinctive: line 285
Version your transformations: Use dbt or version-controlled SQL so changes are auditable.
- Distinctive: line 287
Document lineage: Every column in a mart table should be traceable back to its source.
- Distinctive: line 288
Design for reprocessing: When transformation logic changes, you should be able to rebuild from raw.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
ETL Design Skill
Design ETL (Extract-Transform-Load) and ELT (Extract-Load-Transform) workflows. Cover extraction strategies, transformation patterns, loading approaches, schema management, and orchestration.
Workflow
Step 1: Choose ETL vs ELT
| Factor | ETL | ELT |
| Transform location | Before loading (external compute) | After loading (warehouse compute) |
| Best for | Complex transformations, data cleansing | SQL-centric transformations |
| Tools | Spark, Python, custom code | dbt, warehouse SQL |
| Scalability | Scales with compute cluster | Scales with warehouse |
| Cost model | Separate compute costs | Warehouse compute costs |
| Debugging | Harder (data not yet in warehouse) | Easier (raw data is queryable) |
| Modern preference | Legacy / specialized use cases | Modern cloud warehouse standard |
Recommendation: Use ELT for most modern data warehouse projects. Use ETL when transformations require complex logic not easily expressed in SQL, or when data must be cleansed before it is safe to store.
Step 2: Design Extraction
Source Types and Strategies
| Source Type | Extraction Method | Considerations |
| Transactional DB | CDC or incremental query | Use replication slot for CDC; query on updated_at for incremental |
| REST API | Paginated fetch | Handle rate limits, pagination, authentication refresh |
| File drop | Watch directory / S3 events | Validate file before processing; handle late/duplicate files |
| Streaming | Consumer group | Handle offset management, exactly-once semantics |
| SaaS platform | Managed connector | Fivetran, Airbyte, or native connectors |
| Spreadsheet | Manual upload or API | Validate schema, handle human-entered data quality |
Incremental Extraction Patterns
Timestamp-based:
-- Extract records modified since last successful run
SELECT *
FROM source_table
WHERE updated_at > :last_watermark
AND updated_at <= :current_timestamp
ORDER BY updated_atLog-based (CDC):
Source DB -> WAL/Binlog -> Debezium -> Kafka -> WarehouseSequence-based:
-- Use an auto-incrementing ID for append-only tables
SELECT *
FROM events
WHERE event_id > :last_max_id
ORDER BY event_idFull refresh (when incremental is not possible):
-- Replace entire table; use for small dimension tables
TRUNCATE TABLE target_table;
INSERT INTO target_table SELECT * FROM source_table;Step 3: Design the Transformation Layer
Use a layered transformation architecture:
Raw/Landing -> Staging -> Intermediate -> Marts/PresentationLayer 1: Raw / Landing
- Exact copy of source data
- No transformations
- Append-only with load timestamp
- Serves as audit trail and reprocessing source
-- Raw table structure
CREATE TABLE raw.orders (
_loaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
_source_file STRING,
_raw_data VARIANT -- Store entire payload as semi-structured
);Layer 2: Staging
- Cleaned and typed
- Deduplicated
- Column names standardized
- Source-specific logic applied
-- dbt staging model pattern
-- models/staging/stg_orders.sql
WITH source AS (
SELECT * FROM {{ source('raw', 'orders') }}
),
renamed AS (
SELECT
order_id::INTEGER AS order_id,
customer_id::INTEGER AS customer_id,
TRIM(status) AS order_status,
amount::DECIMAL(12,2) AS order_amount_usd,
TO_TIMESTAMP(created_at) AS created_at,
TO_TIMESTAMP(updated_at) AS updated_at
FROM source
),
deduplicated AS (
SELECT *
FROM renamed
QUALIFY ROW_NUMBER() OVER (PARTITION BY order_id ORDER BY updated_at DESC) = 1
)
SELECT * FROM deduplicatedLayer 3: Intermediate
- Business logic applied
- Joins across sources
- Calculations and derived fields
- Grain transformations
-- models/intermediate/int_order_items_enriched.sql
SELECT
oi.order_item_id,
oi.order_id,
o.customer_id,
o.order_status,
p.product_name,
p.category,
oi.quantity,
oi.unit_price,
oi.quantity * oi.unit_price AS line_total,
CASE
WHEN o.order_status = 'refunded' THEN 0
WHEN o.order_status = 'partially_refunded' THEN oi.quantity * oi.unit_price * (1 - o.refund_pct)
ELSE oi.quantity * oi.unit_price
END AS net_revenue
FROM {{ ref('stg_order_items') }} oi
JOIN {{ ref('stg_orders') }} o ON oi.order_id = o.order_id
JOIN {{ ref('stg_products') }} p ON oi.product_id = p.product_idLayer 4: Marts / Presentation
- Business-user-facing tables
- Pre-aggregated for common queries
- Documented with descriptions
- Optimized for BI tool access
-- models/marts/fct_daily_revenue.sql
SELECT
DATE_TRUNC('day', o.created_at) AS revenue_date,
p.category AS product_category,
c.segment AS customer_segment,
COUNT(DISTINCT o.order_id) AS order_count,
COUNT(DISTINCT o.customer_id) AS customer_count,
SUM(oi.net_revenue) AS net_revenue,
SUM(oi.net_revenue) / NULLIF(COUNT(DISTINCT o.order_id), 0) AS avg_order_value
FROM {{ ref('int_order_items_enriched') }} oi
JOIN {{ ref('stg_orders') }} o ON oi.order_id = o.order_id
JOIN {{ ref('dim_customers') }} c ON o.customer_id = c.customer_id
JOIN {{ ref('dim_products') }} p ON oi.product_id = p.product_id
GROUP BY 1, 2, 3Step 4: Design Loading Strategy
| Strategy | Implementation | Use When |
| Full refresh | DROP + CREATE AS or TRUNCATE + INSERT | Small tables (<1M rows), dimension tables |
| Incremental append | INSERT new records only | Event/fact tables, append-only data |
| Incremental merge | MERGE on key, update existing + insert new | Mutable records with updates |
| Partition replace | Delete partition + insert | Date-partitioned fact tables |
| Snapshot | Capture full state periodically | SCD Type 2, historical tracking |
dbt materialization mapping:
# dbt_project.yml
models:
staging:
+materialized: view # Always fresh, low cost
intermediate:
+materialized: ephemeral # Inline, no table created
marts:
facts:
+materialized: incremental # Append new data
+incremental_strategy: merge
+unique_key: id
dimensions:
+materialized: table # Full refresh dailyStep 5: Handle Schema Evolution
Prepare for upstream schema changes:
def detect_schema_changes(current_schema, expected_schema):
"""Detect and categorize schema changes."""
current_cols = set(current_schema.keys())
expected_cols = set(expected_schema.keys())
changes = {
'new_columns': current_cols - expected_cols, # Added upstream
'dropped_columns': expected_cols - current_cols, # Removed upstream
'type_changes': [], # Type changed
}
for col in current_cols & expected_cols:
if current_schema[col] != expected_schema[col]:
changes['type_changes'].append({
'column': col,
'was': expected_schema[col],
'now': current_schema[col]
})
return changesSchema evolution strategies:
- Additive only: Accept new columns, alert on drops or type changes
- Schema-on-read: Store raw data as JSON/VARIANT, parse in transformations
- Versioned schemas: Maintain schema registry, version transformations
- Contract testing: Fail pipeline if schema violates contract
Step 6: Design Orchestration
# Airflow DAG pattern
extract_orders >> validate_orders >> load_raw_orders
extract_customers >> validate_customers >> load_raw_customers
[load_raw_orders, load_raw_customers] >> run_dbt_staging
run_dbt_staging >> run_dbt_intermediate >> run_dbt_marts
run_dbt_marts >> run_data_tests >> notify_on_completionKey orchestration principles:
- Define dependencies explicitly (DAG)
- Set appropriate timeouts for each task
- Configure retry policies (count, delay, backoff)
- Use sensors or triggers for event-driven starts
- Separate extraction from transformation schedules when needed
Output Format
Deliver an ETL design document with:
- Architecture overview showing data flow from source to presentation
- Extraction design per source with incremental strategy
- Transformation layer design with model lineage
- Loading strategy with materialization choices
- Schema evolution plan
- Orchestration DAG with dependencies and schedules
- Testing strategy with data quality checks at each layer
Examples
Example 1: SaaS Analytics ETL
Fivetran syncs from Stripe, Salesforce, and product DB. dbt transforms through staging, intermediate, and mart layers. Daily full refresh for dimensions, incremental for facts.
Example 2: Event Stream ELT
Kafka events land in S3, Snowpipe loads to raw. dbt transforms events into session-level and user-level aggregations. Micro-batch with 15-minute freshness SLA.
Example 3: Financial Data ETL
Extract from ERP via JDBC, validate against source row counts, transform with fiscal calendar mapping, load with partition-based idempotency, reconcile totals post-load.
Best Practices
- Land raw data first. Always store the unmodified source data before transforming.
- Version your transformations. Use dbt or version-controlled SQL so changes are auditable.
- Test at every layer. Schema tests on staging, business logic tests on intermediate, freshness tests on marts.
- Document lineage. Every column in a mart table should be traceable back to its source.
- Design for reprocessing. When transformation logic changes, you should be able to rebuild from raw.
- Separate concerns. One model per transformation step. Do not combine extraction, cleaning, and business logic.
- Use incremental where possible. Full refreshes become expensive as data grows.
- Monitor data freshness. SLA breaches should trigger alerts before stakeholders notice.
- Handle late-arriving data. Design a strategy for records that arrive after their partition was processed.
- Plan for backfills from day one. Make it easy to reprocess a date range when business logic changes.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

