Cutting ETL Costs by $300K While Replicating Thousands of Tables Daily

Share this :
Engineering Deep Dive

How We Built a 10x Faster Data Replication Pipeline - and Saved $300k a Year

Why we stopped trusting third-party ETL tools and built our own Teradata-to-cloud replication engine using native database commands.

Throughput vs market tools
0 X
Annual licensing savings
$ 0 K
Tables replicated daily
0 S

The Problem With Every Tool We Tried

The reason? They all relied on generic JDBC or ODBC connectors to extract data row by row, or in small batches. At the scale of enterprise data warehouses, that approach simply doesn’t work. We were leaving enormous amounts of native performance on the table.
The insight
Teradata, Redshift, and PostgreSQL all have native, highly optimized bulk-transfer commands built in. No commercial tool we evaluated was using them. We built one that does — and the results weren’t even close.

The Architecture: Native Commands, All the Way Down

The core design principle was simple: at every hop in the pipeline, use the database’s own native bulk-transfer mechanism. Never touch a row iterator when a bulk command is available.

Step 1 : Export with Teradata's WRITE_NOS

Instead of extracting data through a connection and streaming it byte by byte, we used Teradata’s WRITE_NOS command to write data directly to Amazon S3 in bulk. This is a server-side operation – Teradata does the heavy lifting, writing massively parallel output straight to object storage. No driver bottleneck. No memory pressure on the client. Just raw throughput.

Step 2 : Stage in Amazon S3

S3 acts as a high-throughput, decoupled buffer between source and destination. Because both Redshift and PostgreSQL have native S3 import capabilities, the same export step feeds multiple target databases — the Teradata side doesn’t change at all regardless of destination.

Step 3A : Load into Redshift with COPY

Redshift’s COPY command is the fastest way to get data into Redshift, bar none. It reads from S3 in parallel across all compute nodes. We load first into a staging table, then merge into the target using the primary key – giving us a clean, idempotent upsert on every run.

Step 3B : Load into PostgreSQL with aws_s3.table_import_from_s3

When the client expanded the use case to PostgreSQL targets, the architecture barely changed. PostgreSQL’s aws_s3.table_import_from_s3 extension provides the same native-S3-import pattern. The export step was unchanged; we simply wired in a new destination command. This validated that the design was genuinely composable, not just a one-off trick.

Making It Incremental - Without the Complexity

Full-table refreshes are wasteful at scale. We needed incremental replication: only copy rows that are new or changed since the last run. The mechanism for this is a watermark – a record of the highest primary key (or timestamp) seen in the last successful load.

We store watermarks in a dedicated PostgreSQL database. On each run, the pipeline reads the current watermark, passes it to WRITE_NOS as a filter, exports only the delta, loads it into a Redshift staging table, and merges it into the target. Then it writes the new watermark back to Postgres. The whole loop is atomic enough that a failed run simply retries from the last clean checkpoint.

“The staging table + merge pattern is what makes this reliable at scale. New rows are inserted, changed rows are updated — no duplicates, no full refreshes, no data loss.”

Configuration as Code: Making It Accessible to Everyone

A fast pipeline that only your platform team can operate isn’t a product – it’s a prototype. We wanted any data engineer in the organization to be able to onboard a new table in minutes, without reading a line of Python.

The answer was a declarative YAML interface with an intentionally SQL-like syntax. Install the package, write a config file, run it. That’s it.

The SQL-like syntax was deliberate. Any engineer or analyst comfortable with SELECT statements can read and write these configs. The package resolves the watermark, runs the export, handles the staging merge, and updates the checkpoint – all invisible to the consumer.

Read the watermark

The package fetches the last-replicated value for each table from the PostgreSQL checkpoint store.

Export the delta

Teradata's WRITE_NOS exports only rows where the incremental column exceeds the watermark, directly to S3.

Load into staging

Redshift's COPY (or aws_s3.table_import_from_s3) bulk-loads the delta into a temporary staging table.

Merge to target

A MERGE operation upserts staging rows into the target table using the declared primary key - inserts new, updates changed.

Advance the watermark

The new high-water mark is written back to PostgreSQL, ready for the next scheduled run.

What's Under the Hood

ComponentTechnologyRole
SourceTeradataLegacy enterprise data warehouse
ExportWRITE_NOSNative server-side bulk export to S3
Staging layerAmazon S3High-throughput decoupled buffer
Redshift importCOPYNative parallel bulk load
Postgres importaws_s3.table_import_from_s3Native S3-to-Postgres extension
CheckpointingPostgreSQLWatermark and run-state tracking
InterfaceYAML + pipConfig-as-code for consumers
DistributionArtifactoryInternal package hosting

Results

Throughput vs. every commercial tool we benchmarked
0 X
Target databases supported (Redshift + Postgres) from one export step
0 S
Tables replicated incrementally, every day
0 S
Annual licensing cost eliminated
$ 0 K
The package was rolled out incrementally — starting with a handful of pilot tables, battle-tested across every data type we encountered, and expanded team by team until it became the organizational default. It’s now the standard way to move data from Teradata to the cloud within the organization, distributed via Artifactory and maintained as a versioned library.

The Takeaway

The lesson here isn’t specific to Teradata or Redshift. It’s a general principle: generic tools solve the general case, but native tools solve your case. Every major database has bulk-transfer primitives that exist precisely because row-by-row iteration doesn’t scale. Before reaching for a third-party connector, it’s worth asking: what does this database already know how to do really fast?

In our case, the answer was sitting in the documentation the whole time. We just had to build around it.

Want to learn more?

The configuration-as-code interface, watermarking design, and multi-target architecture are all available internally via Artifactory. Reach out to the Data Platform team to get onboarded.