Skip to content

Singer alternative — Singer vs Skippr ​

Singer is an open specification, not a platform. Stitch wrote it around 2016. A tap prints newline-delimited JSON to stdout. A target reads those lines from stdin. The messages are SCHEMA, RECORD, and STATE. Logs go to stderr. If you print a debug line on stdout, the pipe dies. Spec version is 0.3.0. Incremental work is a bookmark in STATE, then FULL_TABLE or INCREMENTAL on the catalog. There is no scheduler, no UI, no lake. singer.io still shows the Unix pipe: tap-exchangeratesapi | target-csv. The directory there lists on the order of a hundred taps and about ten targets. Meltano Hub is where most people find variants now. Qlik owns Stitch, the hosted runner that started this.

Skippr is an open Streamhouse you run as one Rust binary. Write skippr.yml (or the same thing in Python), discover, sync. You query live state over Iceberg ∪ WAL, and the history is ordinary Iceberg in your bucket. Skippr does not speak Singer. ELT into a warehouse is one path, not the product.

FeatureSkipprSinger
DeploySingle Rust binary, your VPC or on-premA spec. You run a tap and a target, or a runner such as Meltano
SchemaIn-stream evolution, sibling columnsSCHEMA before records. A new column can sit unseen until you refresh the catalog
StorageOpen Iceberg on Parquet you ownWhatever target you pipe into
CDCLog-based; fails closed if the dest cannot honourBookmark incremental if that tap implements it. Not log CDC
Queryskipprd query on Iceberg ∪ WAL; history in any Iceberg engineDestination after the pipe. No engine
PricingFree self-hosted engineThe spec is free. Runners and hosted Stitch have their own prices.

What Singer is good at ​

The pipe is honest. Any language can write JSON lines. You can pip install two packages and move a stream without a control plane. The Meltano Singer SDK (Apache-2.0) is how new taps get written in 2026: pagination, state, ACTIVATE_VERSION, optional BATCH. For a source skipprd does not have yet, a Hub tap plus target-jsonl or target-snowflake is a real extract. That is the job the spec was written for.

Where the job is wider ​

Singer is a message format. Production is a runner, a scheduler, a state store, and whoever still maintains that tap. Hub count is not Hub quality. Many original singer-io taps are quiet. MeltanoLabs keeps a smaller default set. When an API moves, the fix is the fork you picked, or you. Schema drift is the same rule Meltano inherited: refresh the catalog or the new column never leaves the tap.

STATE is a bookmark, not a WAL. There is no Iceberg ∪ WAL. There is no skipprd query on in-flight rows. Log-based CDC is not in the spec. BATCH in the SDK is still preview, and the built-in path does not track incremental bookmarks.

Skippr will not run tap-xero or any other Singer listing. If the source you need only exists as a tap, Singer (usually via Meltano) is the narrower extract. If the job is live SQL on Iceberg you run, Singer was never that.

Getting started ​

Install skipprd from the install guide, or pip install skippr. The three tabs write the same skippr.yml. Then discover, sync, and query.

yaml
skippr:
  workspace: analytics
  skipprd_el_storage_mode: local

pipelines:
  orders:
    data_source: data_sources.app_db
    data_sink: data_sinks.lake

data_sources:
  app_db:
    Postgres:
      host: db.internal
      user: skippr_reader
      password: ${APP_DB_PASSWORD}
      database: app
      tables: [orders, customers]
      cdc_mode: snapshot_then_cdc

data_sinks:
  lake:
    AthenaIceberg:
      warehouse: s3://my-iceberg-warehouse/
      glue_database_name: analytics
      athena_workgroup_name: primary
      athena_results_s3_bucket: my-athena-results
      region: us-east-1
    schema_sink: schema_sinks.lake_schema

schema_sinks:
  lake_schema:
    AthenaIceberg:
      warehouse: s3://my-iceberg-warehouse/
      glue_database_name: analytics
      athena_workgroup_name: primary
      athena_results_s3_bucket: my-athena-results
      region: us-east-1
bash
skipprd --workspace analytics --storage-mode local connect data-source postgres \
  --pipeline orders \
  --name app_db \
  --host db.internal \
  --user skippr_reader \
  --password '${APP_DB_PASSWORD}' \
  --database app \
  --tables orders \
  --tables customers \
  --cdc-mode snapshot_then_cdc

skipprd connect data-sink athenaiceberg \
  --pipeline orders \
  --name lake \
  --warehouse s3://my-iceberg-warehouse/ \
  --glue-database-name analytics \
  --athena-workgroup-name primary \
  --athena-results-s3-bucket my-athena-results \
  --region us-east-1

skipprd connect schema-sink athenaiceberg \
  --pipeline orders \
  --name lake_schema
python
from skippr import (
    Config,
    DataSinkAthenaIceberg,
    DataSourcePostgres,
    DataSourcePostgresSourceCdcMode,
    EnvRef,
    LocalStorage,
    Pipeline,
)

cfg = Config().workspace("analytics").storage(LocalStorage())

app_db = cfg.data_source(
    "app_db",
    DataSourcePostgres(
        host="db.internal",
        user="skippr_reader",
        password=EnvRef("APP_DB_PASSWORD"),
        database="app",
        tables=["orders", "customers"],
        cdc_mode=DataSourcePostgresSourceCdcMode.SNAPSHOTTHENCDC,
    ),
)

lake = cfg.data_sink(
    "lake",
    DataSinkAthenaIceberg(
        warehouse="s3://my-iceberg-warehouse/",
        glue_database_name="analytics",
        athena_workgroup_name="primary",
        athena_results_s3_bucket="my-athena-results",
        region="us-east-1",
    ),
    schema_sink="lake_schema",
)

cfg.pipeline("orders", Pipeline(data_source=app_db, data_sink=lake))
cfg.save("skippr.yml")
bash
export APP_DB_PASSWORD='your-postgres-password'
skipprd discover --pipeline orders
skipprd sync --pipeline orders --once
skipprd query "SELECT count(*) FROM analytics.orders"

Which to choose ​

Choose Singer (usually through Meltano) if you need a community tap skipprd does not have, and a warehouse or file after the pipe is enough.

Choose Skippr if you want one binary, live SQL, and Iceberg files that stay yours. Skippr will not execute Singer taps.

Install from Install. Connector and query reference live in Developer Docs. For optional onboarding in your VPC, Enterprise Jumpstart or Contact.