A production-grade batch data pipeline built on Google Cloud Platform. It reads CSV data, validates it, transforms it, and loads it into BigQuery using incremental MERGE logic, with full audit logging and Apache Airflow orchestration.
Every time the pipeline runs, it:
- Extracts data from a CSV file in Google Cloud Storage
- Validates the data β checks for nulls, bad types, out-of-range values
- Transforms the data β cleans, renames, and enriches fields
- Loads it into BigQuery using a MERGE statement (no duplicates, ever)
- Logs every run with row counts, timestamps, and pass/fail status
CSV File (GCS)
β
βΌ
extract.py β reads the CSV into a pandas DataFrame
β
βΌ
validate.py β checks data quality, rejects bad rows
β
βΌ
transform.py β cleans and enriches the data
β
βΌ
load.py β uploads to BigQuery staging table
β
βΌ
MERGE SQL β upserts into the final BigQuery table
β
βΌ
audit log β writes run metadata to BigQuery audit table
Airflow orchestrates all of the above steps on a daily schedule.
batch-data-pipeline-gcp/
β
βββ run_etl.py β entry point: runs the full pipeline manually
β
βββ etl/
β βββ extract.py β reads CSV from GCS into a DataFrame
β βββ transform.py β cleans and transforms the data
β βββ validate.py β data quality checks
β βββ load.py β loads to BigQuery (staging + MERGE)
β
βββ airflow/
β βββ dags/
β βββ batch_pipeline_dag.py β Airflow DAG (daily schedule)
β
βββ sql/
β βββ merge.sql β MERGE statement for idempotent loads
β
βββ scripts/
β βββ setup_gcp.sh β GCP setup script (APIs, buckets, BQ datasets)
β
βββ data/
β βββ sample_data.csv β sample input file for testing
β
βββ logs/
βββ pipeline.log β local run logs
| Tool | Purpose |
|---|---|
| Python 3.10+ | ETL logic (extract, transform, validate, load) |
| Apache Airflow | Pipeline orchestration and scheduling |
| Google BigQuery | Data warehouse (target) |
| Google Cloud Storage | Source file storage |
| Pandas | In-memory data transformation |
| BigQuery Python SDK | Loading data to BQ |
Before running this project, you need:
- A Google Cloud account with billing enabled
- A GCP project created
- The following APIs enabled: BigQuery API, Cloud Storage API
- Python 3.10 or higher installed on your machine
gcloudCLI installed and authenticated
git clone https://github.com/AjayVarma03/batch-data-pipeline-gcp.git
cd batch-data-pipeline-gcppip install -r requirements.txtgcloud auth application-default login
export GOOGLE_CLOUD_PROJECT=your-project-idpython run_etl.pyThis runs extract β validate β transform β load in sequence and writes logs to logs/pipeline.log.
π Pipeline Flow : Extract data from CSV (GCS) Validate data (null checks, data types) Transform data (cleaning & enrichment) Load into BigQuery staging table Run MERGE to update final table Log pipeline execution
# Copy the DAG to your Airflow dags folder
cp airflow/dags/batch_pipeline_dag.py ~/airflow/dags/
# Start Airflow
airflow standalone
# Open the Airflow UI at http://localhost:8080
# Trigger the batch_pipeline_dag manually or wait for the daily scheduleIncremental loading with MERGE The pipeline never does a full reload. Every run uses a MERGE statement in BigQuery β if a row already exists (matched by ID), it updates it; if it's new, it inserts it. This means the pipeline is safe to re-run without creating duplicates.
Idempotency Running the pipeline twice produces the same result as running it once. This is critical for backfill scenarios and recovery from failures.
Data quality before load
The validate.py step runs before any data touches BigQuery. Rows that fail validation are rejected and logged β they never make it into the warehouse.
Audit logging
Every pipeline run writes a record to a pipeline_audit table in BigQuery containing the run timestamp, row counts, validation pass/fail counts, and status. You can query this table to see the full history of pipeline runs.
To reprocess data for a historical date:
python run_etl.py --date 2024-01-15The pipeline reads the file for that date from GCS and reloads it using the MERGE logic. Existing rows are updated, not duplicated.
Local logs are written to logs/pipeline.log. Each run appends to this file with timestamps:
2024-01-15 08:00:01 - INFO - ===== PIPELINE STARTED =====
2024-01-15 08:00:02 - INFO - Extracted 5000 rows from GCS
2024-01-15 08:00:03 - INFO - Validation passed: 4987 rows. Rejected: 13 rows
2024-01-15 08:00:05 - INFO - Loaded 4987 rows to BigQuery staging
2024-01-15 08:00:06 - INFO - MERGE complete. Inserted: 3200, Updated: 1787
2024-01-15 08:00:06 - INFO - ===== PIPELINE COMPLETE =====
Ajay Varma β github.com/AjayVarma03