Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Data ingestion patterns for loading data from cloud storage, APIs, files, and streaming sources into databases. Use when importing CSV/JSON/Parquet files, pulling from S3/GCS buckets, consuming API feeds, or building ETL pipelines.
.claude/skills/ancoleman-ingesting-data/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 3% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 54% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 69% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 40% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 735% | 0% |
This skill provides patterns for getting data INTO systems from external sources.
What is your data source?
├── Cloud Storage (S3, GCS, Azure) → See cloud-storage.md
├── Files (CSV, JSON, Parquet) → See file-formats.md
├── REST/GraphQL APIs → See api-feeds.md
├── Streaming (Kafka, Kinesis) → See streaming-sources.md
├── Legacy Database → See database-migration.md
└── Need full ETL framework → See etl-tools.mddlt (data load tool) - Modern Python ETL:
pythonimport dlt # Define a source @dlt.source def github_source(repo: str): @dlt.resource(write_disposition="merge", primary_key="id") def issues(): response = requests.get(f"https://api.github.com/repos/{repo}/issues") yield response.json() return issues # Load to destination pipeline = dlt.pipeline( pipeline_name="github_issues", destination="postgres", # or duckdb, bigquery, snowflake dataset_name="github_data" ) load_info = pipeline.run(github_source("owner/repo")) print(load_info)
Polars for file processing (faster than pandas):
pythonimport polars as pl # Read CSV with schema inference df = pl.read_csv("data.csv") # Read Parquet (columnar, efficient) df = pl.read_parquet("s3://bucket/data.parquet") # Read JSON lines df = pl.read_ndjson("events.jsonl") # Write to database df.write_database( table_name="events", connection="postgresql://user:pass@localhost/db", if_table_exists="append" )
S3 ingestion:
typescriptimport { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"; import { parse } from "csv-parse/sync"; const s3 = new S3Client({ region: "us-east-1" }); async function ingestFromS3(bucket: string, key: string) { const response = await s3.send(new GetObjectCommand({ Bucket: bucket, Key: key })); const body = await response.Body?.transformToString(); // Parse CSV const records = parse(body, { columns: true, skip_empty_lines: true }); // Insert to database await db.insert(eventsTable).values(records); }
API feed polling:
typescriptimport { Hono } from "hono"; // Webhook receiver for real-time ingestion const app = new Hono(); app.post("/webhooks/stripe", async (c) => { const event = await c.req.json(); // Validate webhook signature const signature = c.req.header("stripe-signature"); // ... validation logic // Ingest event await db.insert(stripeEventsTable).values({ eventId: event.id, type: event.type, data: event.data, receivedAt: new Date() }); return c.json({ received: true }); });
High-performance file ingestion:
rustuse polars::prelude::*; use aws_sdk_s3::Client; async fn ingest_parquet(client: &Client, bucket: &str, key: &str) -> Result<DataFrame> { // Download from S3 let resp = client.get_object() .bucket(bucket) .key(key) .send() .await?; let bytes = resp.body.collect().await?.into_bytes(); // Parse with Polars let df = ParquetReader::new(Cursor::new(bytes)) .finish()?; Ok(df) }
Concurrent file processing:
gopackage main import ( "context" "encoding/csv" "github.com/aws/aws-sdk-go-v2/service/s3" ) func ingestCSV(ctx context.Context, client *s3.Client, bucket, key string) error { resp, err := client.GetObject(ctx, &s3.GetObjectInput{ Bucket: &bucket, Key: &key, }) if err != nil { return err } defer resp.Body.Close() reader := csv.NewReader(resp.Body) records, err := reader.ReadAll() if err != nil { return err } // Batch insert to database return batchInsert(ctx, records) }
For periodic bulk loads:
Source → Extract → Transform → Load → Validate
↓ ↓ ↓ ↓ ↓
S3 Download Clean/Map Insert Count checkKey considerations:
For continuous data flow:
Source → Buffer → Process → Load → Ack
↓ ↓ ↓ ↓ ↓
Kafka In-memory Transform DB Commit offsetKey considerations:
For external API data:
Schedule → Fetch → Dedupe → Load → Update cursor
↓ ↓ ↓ ↓ ↓
Cron API call By ID Insert Last timestampKey considerations:
For database replication:
Source DB → Capture changes → Transform → Target DB
↓ ↓ ↓ ↓
Postgres Debezium/WAL Map schema Insert/UpdateKey considerations:
| Use Case | Python | TypeScript | Rust | Go | |----------|--------|------------|------|-----| | ETL Framework | dlt, Meltano, Dagster | - | - | - | | Cloud Storage | boto3, gcsfs, adlfs | @aws-sdk/, @google-cloud/ | aws-sdk-s3, object_store | aws-sdk-go-v2 | | File Processing | polars, pandas, pyarrow | papaparse, xlsx, parquetjs | polars-rs, arrow-rs | encoding/csv, parquet-go | | Streaming | confluent-kafka, aiokafka | kafkajs | rdkafka-rs | franz-go, sarama | | CDC | Debezium, pg_logical | - | - | - |
references/cloud-storage.md - S3, GCS, Azure Blob patternsreferences/file-formats.md - CSV, JSON, Parquet, Excel handlingreferences/api-feeds.md - REST polling, webhooks, GraphQL subscriptionsreferences/streaming-sources.md - Kafka, Kinesis, Pub/Subreferences/database-migration.md - Schema migration, CDC patternsreferences/etl-tools.md - dlt, Meltano, Airbyte, Fivetranscripts/validate_csv_schema.py - Validate CSV against expected schemascripts/test_s3_connection.py - Test S3 bucket connectivityscripts/generate_dlt_pipeline.py - Generate dlt pipeline scaffoldAfter ingestion, chain to appropriate database skill:
| Destination | Chain to Skill | |-------------|----------------| | PostgreSQL, MySQL | databases-relational | | MongoDB, DynamoDB | databases-document | | Qdrant, Pinecone | databases-vector (after embedding) | | ClickHouse, TimescaleDB | databases-timeseries | | Neo4j | databases-graph |
For vector databases, chain through ai-data-engineering for embedding:
ingesting-data → ai-data-engineering → databases-vector| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 21,667 | 12,615 | -42% | 1 | 1 | 0% | 4,013 | 4,150 | +3% | 0 | 0 | — |
case-02 | pass→pass | 12,905 | 11,129 | -14% | 1 | 1 | 0% | 2,502 | 4,342 | +74% | 0 | 0 | — |
case-03 | pass→pass | 12,035 | 13,714 | +14% | 1 | 1 | 0% | 2,085 | 4,526 | +117% | 0 | 0 | — |
case-04 | pass→pass | 14,772 | 17,113 | +16% | 1 | 1 | 0% | 2,634 | 5,487 | +108% | 0 | 0 | — |
case-05 | pass→pass | 15,497 | 10,800 | -30% | 1 | 1 | 0% | 2,536 | 4,018 | +58% | 0 | 0 | — |
case-06 | pass→pass | 12,950 | 8,794 | -32% | 1 | 1 | 0% | 2,381 | 3,693 | +55% | 0 | 0 | — |
case-07 | fail→pass | 14,276 | 9,971 | -30% | 1 | 1 | 0% | 2,618 | 4,027 | +54% | 0 | 0 | — |
case-08 | fail→pass | 14,139 | 10,806 | -24% | 1 | 1 | 0% | 2,408 | 4,081 | +69% | 0 | 0 | — |
case-09 | pass→pass | 5,311 | 5,946 | +12% | 1 | 1 | 0% | 979 | 3,187 | +226% | 0 | 0 | — |
case-10 | pass→pass | 17,320 | 13,864 | -20% | 1 | 1 | 0% | 2,538 | 4,239 | +67% | 0 | 0 | — |
case-11 | pass→pass | 29,807 | 19,157 | -36% | 1 | 1 | 0% | 2,911 | 5,296 | +82% | 0 | 0 | — |
case-12 | pass→pass | 17,571 | 19,710 | +12% | 1 | 1 | 0% | 2,892 | 5,532 | +91% | 0 | 0 | — |
case-13 | pass→pass | 22,526 | 20,350 | -10% | 1 | 1 | 0% | 3,443 | 5,369 | +56% | 0 | 0 | — |
case-14 | fail→pass | 16,431 | 9,616 | -41% | 1 | 1 | 0% | 2,712 | 3,784 | +40% | 0 | 0 | — |
case-15 | pass→pass | 16,635 | 13,516 | -19% | 1 | 1 | 0% | 2,526 | 3,824 | +51% | 0 | 0 | — |
case-16 | fail→pass | 2,380 | 1,561 | -34% | 1 | 1 | 0% | 275 | 2,296 | +735% | 0 | 0 | — |
case-17 | fail→pass | 10,467 | 1,328 | -87% | 1 | 1 | 0% | 1,470 | 2,291 | +56% | 0 | 0 | — |
case-18 | fail→pass | 3,026 | 1,555 | -49% | 1 | 1 | 0% | 406 | 2,312 | +469% | 0 | 0 | — |
case-19 | fail→pass | 13,411 | 1,767 | -87% | 1 | 1 | 0% | 2,120 | 2,295 | +8% | 0 | 0 | — |
case-20 | fail→pass | 6,924 | 1,859 | -73% | 1 | 1 | 0% | 1,045 | 2,377 | +127% | 0 | 0 | — |
case-21 | fail→pass | 11,140 | 2,621 | -76% | 1 | 1 | 0% | 1,672 | 2,521 | +51% | 0 | 0 | — |
case-22 | fail→pass | 10,050 | 4,112 | -59% | 1 | 1 | 0% | 1,592 | 2,856 | +79% | 0 | 0 | — |
case-23 | pass→pass | 9,091 | 2,159 | -76% | 1 | 1 | 0% | 1,448 | 2,424 | +67% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +48 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.