Meltano and Singer

Meltano and the Singer Specification

Singer is an open specification for extract and load: a tap writes JSON messages to standard output and a target reads them from standard input, so any tap can feed any target through a Unix pipe. There are three main message types: SCHEMA (a JSON Schema for a stream), RECORD (one row) and STATE (a bookmark the next run resumes from). Hundreds of taps exist, of uneven quality; the MeltanoLabs Singer SDK has become the usual way to write new ones.

Meltano 624,457 (github.com/meltano/meltano (https://github.com/meltano/meltano 2,644 ), MIT, 4.4.0 on 29 September 2026) manages Singer plugins as a project: meltano add installs each plugin into its own virtual environment, meltano.yml holds their configuration, secrets come from the environment (TARGET_POSTGRES_PASSWORD), and meltano run tap-csv target-postgres pipes one into the other while storing state. In 4.x the plugin type is optional (meltano add tap-csv, not meltano add extractor tap-csv). ingest/meltano/run.sh exported BookNest's books table to CSV and ran the pair in python:3.12-slim:

meltano.yml (excerpt): the project after meltano add and meltano config setYAML
plugins:
  extractors:
  - name: tap-csv
    variant: meltanolabs
    pip_url: git+https://github.com/MeltanoLabs/tap-csv.git
    config:
      files:
      - entity: books
        path: data/books.csv
        ...
  loaders:
  - name: target-postgres
    variant: meltanolabs
    pip_url: meltanolabs-target-postgres
    config:
      host: l2-pg
      ...
Output
--- Singer messages from the tap
{"type":"SCHEMA","stream":"books","schema":{"properties":{"book_id":{"type":["string",...
{"type":"RECORD","stream":"books","record":{"book_id":"1","title":"The Quiet Harbor",
"genre":"Fiction","price":"14.99"},"time_extracted":"2026-10-02T0...
--- meltano run
... target-postgres Reader 'target-postgres' completed processing 8 lines of input
(1 schemas, 6 records, ...
... meltano      Run completed

Eight lines carried one schema, six records and bookkeeping messages such as state. Note the schema: tap-csv types every column as a string, so meltano_raw.books.price arrived as text, next to the target's _sdc_* metadata columns. Singer moves data faithfully but types it only as well as the tap describes it.