<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Peter Fabricius</title>
    <description>The latest articles on DEV Community by Peter Fabricius (@pfabricius).</description>
    <link>https://dev.to/pfabricius</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1937186%2Fb6457a99-a04f-4ffa-b4a7-25674c2bfecc.png</url>
      <title>DEV Community: Peter Fabricius</title>
      <link>https://dev.to/pfabricius</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pfabricius"/>
    <language>en</language>
    <item>
      <title>Writing Iceberg tables with Apache Hop and DuckDB</title>
      <dc:creator>Peter Fabricius</dc:creator>
      <pubDate>Fri, 19 Jun 2026 15:16:04 +0000</pubDate>
      <link>https://dev.to/pfabricius/writing-iceberg-tables-with-apache-hop-and-duckdb-2li</link>
      <guid>https://dev.to/pfabricius/writing-iceberg-tables-with-apache-hop-and-duckdb-2li</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;With my &lt;a href="https://github.com/pfabrici/iceduck" rel="noopener noreferrer"&gt;Iceduck&lt;/a&gt; project, I’ve been diving deep into Data Lakehouse architecture and the possibilities of the Modern Data Stack. Initially, I experimented with PySpark, PyIceberg, and similar tools in Jupyter Notebooks and via the Spark CLI. But I soon asked myself: How would this work with more traditional ETL tools—and without Spark?&lt;/p&gt;

&lt;p&gt;Around the same time, I read about DuckDB’s Iceberg integration. A natural next step was to use the DuckDB JDBC driver to write to and read from the Data Lakehouse directly within an ETL tool. The JDBC driver creates an in-memory DuckDB instance, which communicates with the Data Lakehouse and its REST catalog via the DuckDB Iceberg extension. All that’s required is setting up two secrets in DuckDB and attaching the catalog, as outlined in the DuckDB documentation.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Open-Source Test Setup
&lt;/h1&gt;

&lt;p&gt;For my showcase, I wanted to rely entirely on open-source components. Here’s what I put together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/pfabrici/iceduck" rel="noopener noreferrer"&gt;Iceduck&lt;/a&gt;  as a local Data Lakehouse platform, using Apache Polaris as the catalog&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://hop.apache.org" rel="noopener noreferrer"&gt;Apache Hop&lt;/a&gt; as a Java-based data integration tool&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://duckdb.org/" rel="noopener noreferrer"&gt;DuckDB JDBC Treiber&lt;/a&gt; as the bridge between ETL and the Data Lakehouse. It is already contained in the Apache Hop package&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.openplzapi.org" rel="noopener noreferrer"&gt;OpenPLZApi&lt;/a&gt; as a sample data source&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I won’t cover the installation of Iceduck or Hop here, as their respective project pages provide detailed instructions.&lt;/p&gt;

&lt;p&gt;Apache Hop is a low-code data integration tool with a graphical interface. A pipeline that pulls JSON data from a REST API, processes it, and writes it to a target table looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwc7rpyy3jm34kiknp6lu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwc7rpyy3jm34kiknp6lu.png" alt="Apache Hop pipeline overview" width="722" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This pipeline would look identical if you were writing the data to a relational database—except instead of a DuckDB connection, you’d use a Postgres, MariaDB, Oracle, or similar connection. Behind the scenes, however, things work differently: the DuckDB driver itself acts as the database during pipeline execution.&lt;/p&gt;

&lt;p&gt;In this database, a connection initialization script stored in the metadata creates the Data Lakehouse credentials as secrets, attaches the Iceberg catalog, and maps the database schema to the Data Lakehouse. This allows DuckDB to interact directly with the Data Lakehouse, enabling table and content manipulation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5dozwqpcvzcgk6vhp68k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5dozwqpcvzcgk6vhp68k.png" alt="DuckDB connection initialization and catalog attachment" width="750" height="852"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The actual data writing happens in the final step of the pipeline: the "write federalStates to Iceberg" transform, which is a "Table Output" step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgw3cv831tgk996cbtot9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fgw3cv831tgk996cbtot9.png" alt="Table Output step in Apache Hop" width="800" height="794"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Key Learnings
&lt;/h1&gt;

&lt;p&gt;While this approach works surprisingly well, there are a few lessons I’ve learned along the way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing to two Iceberg tables in parallel within a single pipeline fails. It seems there are issues with the catalog in this scenario.&lt;/li&gt;
&lt;li&gt;Each dataset results in a new Parquet file being written.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This experiment showed that integrating a Data Lakehouse with traditional ETL tools like Apache Hop is not only possible but also straightforward—thanks to DuckDB’s flexibility and the power of open-source components. While there are some limitations, the approach opens up new possibilities for data engineers looking to modernize their stacks without abandoning familiar tools.&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>tutorial</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Iceduck: A Local Data Lakehouse Stack for Learning (No Cloud Needed)</title>
      <dc:creator>Peter Fabricius</dc:creator>
      <pubDate>Mon, 15 Jun 2026 08:49:30 +0000</pubDate>
      <link>https://dev.to/pfabricius/iceduck-a-local-data-lakehouse-stack-for-learning-no-cloud-needed-26e1</link>
      <guid>https://dev.to/pfabricius/iceduck-a-local-data-lakehouse-stack-for-learning-no-cloud-needed-26e1</guid>
      <description>&lt;p&gt;I built &lt;strong&gt;&lt;a href="https://github.com/pfabrici/iceduck" rel="noopener noreferrer"&gt;Iceduck&lt;/a&gt;&lt;/strong&gt;, an open-source &lt;strong&gt;Data Lakehouse stack&lt;/strong&gt; that runs &lt;strong&gt;locally&lt;/strong&gt; with Docker Compose. It combines &lt;strong&gt;MinIO, Apache Iceberg (via Polaris), Trino, Postgres, Spark, DuckDB, and Jupyter&lt;/strong&gt; – all without cloud dependencies or costs.&lt;/p&gt;

&lt;p&gt;Iceduck lets you &lt;strong&gt;explore open-source tools&lt;/strong&gt; like Apache Iceberg,DuckDB and Trino &lt;strong&gt;on your own machine&lt;/strong&gt;, making it ideal for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Learning Data Lakehouse concepts&lt;/li&gt;
&lt;li&gt;Prototyping data pipelines&lt;/li&gt;
&lt;li&gt;Testing integrations between tools&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s Inside?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MinIO&lt;/strong&gt; for S3-compatible storage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apache Polaris&lt;/strong&gt; as a REST catalog for Iceberg&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DuckDB&lt;/strong&gt;, &lt;strong&gt;Trino&lt;/strong&gt;, &lt;strong&gt;Spark&lt;/strong&gt; as query engines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Postgres&lt;/strong&gt; as a metastore&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jupyter&lt;/strong&gt; for interactive exploration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the details (setup, usage, and configuration) are in the &lt;strong&gt;&lt;a href="https://github.com/pfabrici/iceduck#readme" rel="noopener noreferrer"&gt;README&lt;/a&gt;&lt;/strong&gt;. I’d love to hear your thoughts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Would you use this for learning or testing?&lt;/li&gt;
&lt;li&gt;What’s missing or could be improved?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/pfabrici/iceduck" rel="noopener noreferrer"&gt;pfabrici/iceduck&lt;/a&gt; (Apache 2.0 License)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#dataengineering&lt;/code&gt; &lt;code&gt;#opensource&lt;/code&gt; &lt;code&gt;#datalakehouse&lt;/code&gt; &lt;code&gt;#docker&lt;/code&gt; &lt;code&gt;#apacheiceberg&lt;/code&gt;&lt;/p&gt;

</description>
      <category>dataengineering</category>
      <category>learning</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
