DEV Community

Cover image for Snowflake Openflow: Managed Apache NiFi for Ingestion & Connectors
Gowtham Potureddi
Gowtham Potureddi

Posted on

Snowflake Openflow: Managed Apache NiFi for Ingestion & Connectors

snowflake openflow is the ingest play the data cloud was missing — a fully managed Apache NiFi service that runs inside Snowflake's perimeter, lets you wire dozens of source systems (SaaS apps, operational databases, object stores, message queues) to Snowflake tables with a visual flow canvas, and ships custom-processor extensibility you cannot get from openflow vs fivetran style plug-and-play vendors. For a decade, teams have run NiFi on their own EC2 fleets or Kubernetes clusters to power complex routing and in-flight transformation; Openflow takes that operational pain away while preserving the full NiFi programming model.

This guide is the senior-DE walkthrough you wished existed the first time an interviewer asked "when do you reach for snowflake nifi instead of Fivetran?" or "how does managed nifi change the build-vs-buy calculus for snowflake ingestion?" It covers the NiFi mental model inside Openflow (processors, flow files, relationships, provenance), the openflow runtime topology (Connect runtime per cloud + region, governed flows, role-based publication), the snowflake source connectors catalog (Salesforce, Postgres CDC, S3, Kafka, custom NAR bundles), schema-evolution policy options for apache nifi snowflake flows that need to survive column drift in 2026, the explicit openflow vs fivetran vs Airbyte vs Snowpipe decision matrix, and the production patterns (cost model, monitoring, back-pressure, exactly-once semantics) that determine whether your openflow connectors rollout ships or stalls. Each section pairs a teaching block with a Solution-Tail interview answer — code, a step-by-step trace, an output table, then a concept-by-concept breakdown of why it works.

PipeCode blog header for Snowflake Openflow — bold white headline 'Snowflake Openflow' with subtitle 'Managed Apache NiFi · ingestion · connectors' over a flow-canvas card on the left feeding a Snowflake-prism warehouse cube on the right via glowing flow-file arrows on a dark gradient with purple, green, orange, and blue accents and a small pipecode.ai attribution.

When you want hands-on reps immediately after reading, drill the ETL & pipeline practice library →, rehearse on medium-difficulty ETL problems →, and sharpen the SQL axis with the SQL practice library →.


On this page


1. Why Openflow — Snowflake's ingest play in 2026

Openflow is managed Apache NiFi running inside Snowflake — visual flows, custom processors, and a connector catalog that closes the gap between SaaS ETL and BYO pipelines

The one-sentence invariant: Openflow is Snowflake's managed Apache NiFi service that runs as a Connect runtime inside the data cloud, gives you the full NiFi programming model (processors, flow files, relationships, provenance), ships a growing catalog of first-party snowflake source connectors, and lets you write custom processors when the catalog is not enough. Every other comparison — openflow vs fivetran, apache nifi snowflake, snowflake data integration, snowflake ingestion cost model — follows from those four properties: managed runtime, full NiFi, first-party connector catalog, custom-processor escape hatch.

The four axes interviewers actually probe.

  • Connector breadth. Openflow ships a first-party catalog (Salesforce, Workday, SharePoint, Box, Slack, ServiceNow, Postgres CDC, MySQL CDC, S3, GCS, Kafka, Pulsar) plus the entire OSS NiFi processor library. Fivetran/Airbyte have wider SaaS-app coverage but no way to extend past the catalog; Openflow lets you write a custom Processor in Java when no first-party connector exists.
  • Runtime. Openflow runs on Connect runtimes — Snowflake-managed compute deployed once per cloud + region. You do not provision VMs, you do not run a NiFi cluster, you do not own ZooKeeper. The openflow runtime is the unit of cost, the unit of network reach, and the unit of governance.
  • Governance. Every flow is a versioned, named, role-protected resource inside Snowflake. Role-based publication (OPENFLOW_ADMIN publishes, OPENFLOW_DEVELOPER edits, OPENFLOW_VIEWER reads) plus per-flow object-level grants make Openflow fit Snowflake's existing RBAC story — something openflow vs fivetran head-to-head comparisons never quite cover.
  • Cost. Two-axis pricing: a per-runtime fixed cost (the always-on compute that hosts your flows) plus a per-flow-file processed credit cost. The cost model is closer to a Kubernetes cluster than to a per-seat SaaS connector — important when you do the buy-vs-build math.

The DSL split — same NiFi DSL, different operational shape.

  • Standalone NiFi ships a Java/Scala DSL, the visual flow canvas in the NiFi UI, and a clustering model that you self-operate (ZooKeeper, multi-node coordination, S3 state). You think in terms of "I deploy a 3-node NiFi cluster behind an ALB and write my flows in the canvas."
  • Openflow ships the same NiFi DSL, the same visual canvas, and the same processor library — but you do not see the cluster. You think in terms of "I provision a Connect runtime per cloud + region, publish my flow to that runtime, grant read/write to a role." The mental model collapses from "run a cluster" to "deploy a flow."

The 2026 reality — what changed since Openflow GA.

  • GA cadence. Openflow moved from public preview in mid-2024 to GA on AWS in late 2025 and on Azure in early 2026. GCP support followed shortly after; multi-cloud Connect runtimes are the default deployment shape in 2026.
  • First-party connectors. The first-party connector catalog grew from ~10 sources at preview to 50+ in 2026, including Workday, NetSuite, ServiceNow, SharePoint, Box, Slack, plus Postgres / MySQL / SQL Server / Oracle CDC.
  • Custom processors. Snowflake added NAR-bundle publication so customers and partners can ship custom processors as signed Snowflake artifacts. The custom processor escape hatch — write Java, package as NAR, publish to your Snowflake account — is now production-ready.
  • Snowpipe integration. Openflow flows can drop into Snowpipe-watched stages, letting you mix the two ingest paths: Openflow for SaaS / DB sources, Snowpipe for high-volume cloud-storage drops. The openflow vs fivetran matrix in 2026 is really four-way (Openflow, Fivetran, Airbyte, Snowpipe), not two-way.

What interviewers listen for.

  • Do you say "Openflow is managed NiFi running inside Snowflake" in the first sentence? — senior signal.
  • Do you describe ingestion as "a flow canvas of processors connected by back-pressured queues, with full provenance on every flow file"? — required answer.
  • Do you mention "the custom processor escape hatch via NAR bundles" unprompted? — senior signal.
  • Do you push back on "Openflow replaces Fivetran" with "they target different operational shapes — Fivetran is SaaS connectors as a service, Openflow is NiFi as a service"? — senior signal.

Worked example — same SaaS sync, three architectures

Detailed explanation. The cleanest way to see what Openflow brings is to run the same use case — sync Salesforce accounts into a Snowflake table every 15 minutes — through three architectures and watch what each one costs in terms of code, infra, and governance. Fivetran reads as "connect and forget"; Airbyte OSS reads as "host the connector yourself"; Openflow reads as "wire processors on a managed canvas." The output table is identical; the operational shape is wildly different.

Question. Sketch the architecture for "every 15 minutes, pull modified Salesforce Account rows into a Snowflake ACCOUNTS table" using Fivetran, Airbyte OSS, and Openflow. Highlight where the engineering work lives in each.

Input.

Source Target Cadence SLA
Salesforce Account (SOQL) Snowflake ACCOUNTS 15 minutes 99.9% on-time

Code.

# Fivetran — SaaS connector as a service
Setup steps:
  1. UI: connect Salesforce OAuth
  2. UI: pick destination = Snowflake
  3. UI: set sync frequency = 15 min
  4. Done. Fivetran owns the connector, the schema, the runtime, the retries.
Enter fullscreen mode Exit fullscreen mode
# Airbyte OSS — connector as code, you operate it
# docker-compose.yml on your own VM or K8s cluster
services:
  airbyte-server:    { image: airbyte/server:0.55 }
  airbyte-worker:    { image: airbyte/worker:0.55 }
  airbyte-webapp:    { image: airbyte/webapp:0.55 }
  airbyte-temporal:  { image: airbyte/temporal }
# Then UI: configure Salesforce source + Snowflake destination + 15-min schedule.
# You own the host, the upgrades, the secrets, the network egress, the on-call.
Enter fullscreen mode Exit fullscreen mode
# Openflow — managed NiFi flow canvas inside Snowflake
Setup steps:
  1. SQL: CREATE OPENFLOW RUNTIME aws_us_east_1_runtime ...;
  2. UI: open flow canvas, drag QuerySalesforce -> ConvertRecord -> PutSnowflakeRecord
  3. UI: set schedule cron = */15 * * * *
  4. SQL: GRANT USAGE ON FLOW sf_accounts TO ROLE openflow_developer;
  5. Publish.
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. Fivetran owns everything from "Salesforce credentials" to "rows in Snowflake" — you give it OAuth and a destination, you pay per monthly active row. There is no flow canvas, no transform layer, and no escape hatch.
  2. Airbyte OSS gives you the connector for free, but you operate the host (or pay for Airbyte Cloud). You own the on-call rotation when a Salesforce API change breaks the connector — until the OSS contributor merges the fix.
  3. Openflow runs as a managed NiFi flow inside Snowflake. You provision the openflow runtime once per cloud + region, then wire up a small flow canvas (QuerySalesforceConvertRecordPutSnowflakeRecord). Snowflake owns the runtime, you own the flow.
  4. The interesting axis: Openflow is the only option of the three that lets you insert a transformation step in-flight (a RouteOnAttribute to drop test accounts, a JoltTransformJSON to flatten nested fields) without a separate dbt run.
  5. End result: Fivetran is fastest to set up; Airbyte is cheapest at scale if you already operate K8s; Openflow is the only one that scales to non-SaaS sources (CDC, file drops, custom processors) without leaving the platform.

Output.

Aspect Fivetran Airbyte OSS Openflow
Setup time minutes hours minutes (after runtime exists)
Custom transform none in-flight none in-flight yes (NiFi processors)
Custom connector no yes (Python CDK) yes (Java NAR bundle)
Runtime ownership Fivetran you Snowflake
Cost shape per MAR per VM + per row per runtime + per flow file

Rule of thumb. If the source is a popular SaaS app and you only need raw extract, Fivetran is the cheapest engineering decision. If you need in-flight transformation, custom routing, or non-SaaS sources alongside SaaS, Openflow's NiFi power pays for the flow-canvas learning curve.

Worked example — Openflow as the "platform for ingest"

Detailed explanation. Senior data engineers ask a different question than juniors. Junior: "which connector should I use for this one source?" Senior: "what is my platform for ingest going to look like in 3 years across 50 sources?" Openflow's answer is "one Connect runtime per cloud + region, one flow per source, one RBAC role per environment." That single-platform answer is the senior interview signal.

Question. Design a 3-year ingest platform that pulls from 12 SaaS apps, 8 operational databases (CDC), and 5 S3 / GCS drop zones into Snowflake. Show how Openflow becomes the single ingest plane.

Input.

Source class Count Pattern
SaaS app (Salesforce / HubSpot / Workday / NetSuite / etc.) 12 poll API every 15 min
Operational DB (Postgres / MySQL / SQL Server / Oracle) 8 CDC stream
Object store (S3 / GCS) 5 event-driven file drop

Code.

-- 1) One runtime per cloud + region (the platform plane)
CREATE OPENFLOW RUNTIME aws_us_east_1_runtime
  CLOUD = AWS
  REGION = 'us-east-1'
  SIZE = MEDIUM
  AUTO_SUSPEND = 600;

CREATE OPENFLOW RUNTIME aws_eu_west_1_runtime
  CLOUD = AWS
  REGION = 'eu-west-1'
  SIZE = SMALL
  AUTO_SUSPEND = 600;

-- 2) Three flow templates — one per source class
-- saas_template: QueryX -> ConvertRecord -> PutSnowflakeRecord
-- cdc_template:  CaptureChangeMySQL -> RouteOnAttribute(op) -> PutSnowflakeRecord
-- s3_template:   ListS3 -> FetchS3Object -> InferAvroSchema -> PutSnowflakeRecord

-- 3) One role per environment
CREATE ROLE openflow_admin_prod;
CREATE ROLE openflow_developer_prod;
CREATE ROLE openflow_viewer_prod;
GRANT USAGE ON RUNTIME aws_us_east_1_runtime TO ROLE openflow_developer_prod;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. The Connect runtime is the unit of cost and the unit of network reach. Two runtimes (one per region) cover 100% of the source surface without piling per-source VMs.
  2. The three flow templates collapse the matrix from 25 sources × custom code to 25 sources × 3 templates. Engineers clone a template, point it at a new source, and ship.
  3. Role-based publication means production flows can only be published by an OPENFLOW_ADMIN_PROD role. Developers can edit drafts in OPENFLOW_DEVELOPER_PROD but cannot promote to production.
  4. The custom processor escape hatch covers the few sources outside the catalog (e.g. an internal HR system with a bespoke REST API). Write a Processor in Java, package as a NAR, publish to the runtime.
  5. Senior interview point: this is a platform answer, not a connector answer. The runtime is the noun; the flows are verbs against it.

Output.

Plane Count Owns
Connect runtimes 2 (per region) compute + network + lifecycle
Flow templates 3 (SaaS / CDC / S3) source class patterns
Concrete flows 25 one per source
RBAC roles 3 (admin / dev / viewer) publication + edit + read

Rule of thumb. A senior answer treats Openflow as the ingest platform plane, not a connector toolbox. Once you have a runtime + a small set of templates + RBAC roles, adding source 26 is a flow-clone, not a project.

Worked example — when Openflow is the wrong answer

Detailed explanation. Pretending Openflow is the right answer for every ingestion problem is the failure mode senior interviewers probe. The honest answer is: Openflow is the wrong choice for two common patterns — extremely high-volume cloud-storage drops where Snowpipe is the order-of-magnitude cheaper option, and SaaS-only pipelines where Fivetran's per-MAR pricing beats Openflow's per-flow-file pricing.

Question. Identify two source patterns where Openflow is the wrong tool and explain why.

Input.

Pattern Volume Source surface
Continuous S3 event drops 100M files/day one bucket, one schema
50 SaaS connectors, no transform needed 12M MAR varied SaaS

Code.

-- Wrong: Openflow for high-volume S3 drops
-- ListS3 -> FetchS3Object -> PutSnowflakeRecord at 100M files/day
--   costs >> Snowpipe auto-ingest credits.

-- Right: Snowpipe auto-ingest
CREATE PIPE s3_landing_pipe
  AUTO_INGEST = TRUE
  AS COPY INTO landing FROM @s3_stage;
-- Snowpipe owns the file detection (SNS/SQS), bills only on COPY.

-- Wrong: Openflow for 50 SaaS sources, no in-flight transforms
-- 50 flows × per-flow-file credits >> Fivetran flat MAR pricing.

-- Right: Fivetran for SaaS-only, Openflow for the long-tail / CDC / custom
-- (hybrid plane: each tool where it wins)
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. For 100M cloud-storage drops/day, the dominant cost in Openflow is the per-flow-file credit charge. Snowpipe is purpose-built for this and is typically an order of magnitude cheaper.
  2. For 50 SaaS sources where you only need raw extract (no in-flight transform), Fivetran's per-MAR pricing usually beats Openflow's per-runtime + per-flow-file model.
  3. The senior answer is hybrid: Snowpipe for cloud-storage drops, Fivetran for plug-and-play SaaS, Openflow for the long tail (CDC, custom processors, complex routing). All three coexist; none is a universal hammer.
  4. The signal for "Openflow wins" is one of: in-flight transformation, custom processor, CDC from an operational DB, complex routing across multiple destinations.

Output.

Pattern Tool Why
100M S3 files/day, no transform Snowpipe per-COPY billing wins on volume
50 SaaS sources, raw extract Fivetran per-MAR pricing + zero infra
8 operational DB CDC Openflow NiFi CDC processors + routing
Long-tail custom REST Openflow NAR-bundle custom processor

Rule of thumb. Don't pick a single ingest tool — pick a portfolio. Openflow wins when you need NiFi power; Snowpipe wins on cloud-storage drops; Fivetran/Airbyte win on pure SaaS extract.

Senior interview question on the ingest portfolio

A senior interviewer often opens with: "You're joining a team that already runs Fivetran for SaaS, Snowpipe for S3, and a hand-rolled Lambda for one weird REST source. They want to add Openflow. Walk me through how you decide what moves to Openflow, what stays, and what the migration plan looks like."

Solution Using a 4-question ingest portfolio framework

Decision framework — when to move a source to Openflow

1. What kind of source is it?
   - Cloud storage drops    → keep on Snowpipe (cheaper at volume)
   - SaaS app, raw extract   → keep on Fivetran (per-MAR pricing wins)
   - CDC / DB / custom REST → move to Openflow (NiFi power needed)

2. Do you need in-flight transform / routing?
   - No  → don't move; raw extract is cheaper on the existing tool
   - Yes → move to Openflow; native NiFi processors handle it

3. Do you need a custom connector?
   - No  → keep on the catalog tool that already covers it
   - Yes → move to Openflow; write a NAR-bundle custom processor

4. What is the volume?
   - > 100M events/day, no transform → keep on Snowpipe
   - < 100M events/day, mixed shape  → Openflow is competitive
Enter fullscreen mode Exit fullscreen mode

Step-by-step trace.

Source today Q1 kind Q2 transform Q3 custom Q4 volume Move?
S3 landing → Snowpipe cloud drop no no 200M/day stay on Snowpipe
Salesforce → Fivetran SaaS no no 1M MAR stay on Fivetran
Postgres CDC → Lambda DB CDC yes (route) no 5M/day move to Openflow
Weird REST → Lambda custom no yes 100K/day move to Openflow

After the 4-question pass, two of the four sources move and two stay. The migration plan is a flow-by-flow port, not a platform swap.

Output:

Source Tool after migration Why
S3 landing Snowpipe volume wins on per-COPY pricing
Salesforce Fivetran raw extract, per-MAR wins
Postgres CDC Openflow NiFi CDC + routing in-flight
Weird REST Openflow custom Java NAR processor

Why this works — concept by concept:

  • Portfolio thinking — the answer is never "one tool for all ingest." It is a portfolio where each tool covers its sweet spot and Openflow takes the long tail. Asking the source-kind question first short-circuits a lot of false dichotomies.
  • Transform-in-flight is the Openflow wedge — the moment you need to route, transform, or enrich during ingest, Openflow's processors win. Catalog tools (Fivetran/Airbyte) cannot do this; Snowpipe cannot either.
  • Custom processor escape hatch — the NAR bundle lets you absorb sources that no catalog covers without leaving the platform. This is the "platform plane" benefit you cannot get from per-source Lambdas.
  • Volume crosses a threshold — for very high-volume cloud-storage drops, Snowpipe's per-COPY pricing dominates. Don't move what is already cheap.
  • Cost — migration cost is per-flow (low) once the runtime exists. The portfolio plan keeps your existing investments intact and only moves sources that genuinely benefit.

ETL
Topic — etl
ETL portfolio design problems

Practice →

ETL Topic — etl · medium Medium-difficulty ingestion problems

Practice →


2. Apache NiFi architecture inside Openflow

apache nifi snowflake is processors + flow files + back-pressured queues — Openflow runs the whole NiFi model inside Snowflake-managed compute

The mental model in one line: a NiFi flow is a directed graph of processors (units of work) connected by relationships (typed edges) along which flow files (envelope around the payload + metadata) travel, with every queue back-pressured and every flow file tracked end-to-end by provenance; Openflow runs this entire model inside Snowflake-managed compute so you never see the cluster. Once you say that out loud, every apache nifi snowflake interview question becomes a deduction from those four primitives: processor, flow file, relationship, provenance.

Visual diagram of NiFi inside Openflow — a horizontal flow of 5 processor blocks connected by back-pressured arrows (ListS3 → FetchS3Object → RouteOnAttribute → ConvertRecord → PutSnowflakeRecord), with a provenance side panel listing audit chips, on a light PipeCode card.

The four core primitives.

  • Processor — a discrete unit of work. Each processor has typed inputs (incoming relationships) and typed outputs (outgoing relationships like success, failure, original). Processors are configured via properties (e.g. Bucket Name, Object Key Prefix). The NiFi processor library ships hundreds out of the box; Openflow ships a curated first-party catalog plus the OSS library.
  • Flow file — the unit of data. A flow file is a (payload, attributes) envelope where the payload is the bytes (a JSON record, a CSV row, an S3 object) and the attributes are a Map<String, String> of metadata (filename, mime.type, s3.bucket, uuid, custom attributes set by upstream processors).
  • Relationship — a typed edge between processors. Every processor emits flow files on one or more relationships (success, failure, retry, original, unmatched, etc.) and you wire the canvas to consume those relationships into downstream processors. This is the typed-routing primitive that catalog tools don't have.
  • Provenance — the audit log of every flow file's journey. Provenance records who created the flow file, every processor it touched, every attribute change, and where it ended up. This is the lineage primitive that powers governance — you can answer "where did this row come from?" months later.

Back-pressured queues — the safety net.

  • Queues are the connectors. Between any two processors sits an in-memory + disk-backed queue. Each queue has a maximum size (count or bytes); when full, the upstream processor pauses.
  • Back-pressure flows upstream automatically. If PutSnowflakeRecord cannot keep up with FetchS3Object, the queue between them fills; FetchS3Object pauses; the queue before that fills; ListS3 pauses. The system gracefully slows itself to the slowest downstream.
  • Penalisation and prioritisation. Failed flow files can be penalised (sent back to the queue with a delay) or sent to the failure relationship for explicit handling. Queues can be priority-ordered (FirstInFirstOutPrioritizer, OldestFlowFileFirstPrioritizer).

Provenance — full lineage of every flow file.

  • Every event captured. RECEIVE (flow file created), SEND (flow file emitted to external system), FORK / JOIN (one flow file becomes many or vice versa), ATTRIBUTES_MODIFIED, CONTENT_MODIFIED, DROP (flow file removed).
  • Provenance is queryable. The NiFi UI provides a provenance browser; Openflow exposes it as queryable Snowflake tables in the OPENFLOW.PROVENANCE schema.
  • This is the lineage audit story. Compliance teams ask "where did this customer row come from?" Provenance answers it without a separate lineage tool.

Run inside Snowflake-managed compute.

  • Connect runtime = the cluster you don't see. Snowflake provisions and manages the NiFi cluster (multiple nodes, ZooKeeper, leader election, state storage). You see one logical runtime; under the hood it's a horizontally-scaled cluster.
  • Per-runtime sizing. SIZE = SMALL | MEDIUM | LARGE | XLARGE controls the compute. Auto-suspend on idle keeps cost low when flows are scheduled rarely.
  • Network reach. A runtime lives in a specific cloud + region and gets a stable egress IP for whitelisting on third-party APIs. You provision one runtime per network boundary you care about.

Common interview probes on the NiFi model.

  • "What is a flow file?" — payload + attributes envelope.
  • "What is a relationship?" — typed edge between processors (success / failure / original / ...).
  • "How does back-pressure work?" — full queues pause upstream processors automatically.
  • "Where does provenance live in Openflow?" — queryable Snowflake tables under OPENFLOW.PROVENANCE.
  • "What is a NAR bundle?" — packaged custom processors you publish to a runtime.

Worked example — a 5-processor S3 → Snowflake flow

Detailed explanation. The Hello World of Openflow: pull files from an S3 prefix, fetch each one, drop test files, parse the records, and upsert into a Snowflake table. Five processors, four relationships, one flow. The same shape applies to dozens of real flows — the only variation is which processors you use at the head and tail.

Question. Build a 5-processor flow that ingests S3 JSON-line files into a Snowflake EVENTS table, dropping any file whose key starts with test/.

Input.

s3.bucket s3.key size mime.type
events-landing prod/2026-06-22/part-001.jsonl 12.4 MB application/x-ndjson
events-landing test/2026-06-22/part-002.jsonl 1.1 MB application/x-ndjson
events-landing prod/2026-06-22/part-003.jsonl 8.2 MB application/x-ndjson

Code.

# Flow on the canvas — 5 processors, 4 connectors

[ListS3]
  Bucket Name = events-landing
  Prefix = ""
  Schedule = 30 sec
  Relationships: success → [FetchS3Object]

[FetchS3Object]
  Bucket Name = ${s3.bucket}
  Object Key  = ${s3.key}
  Relationships: success → [RouteOnAttribute], failure → [LogAndAlert]

[RouteOnAttribute]
  Routing Strategy = Route to Property name
  Property "drop_test": ${s3.key:startsWith('test/')}
  Property "keep":      ${s3.key:startsWith('prod/')}
  Relationships:
    drop_test → [auto-terminated]
    keep      → [ConvertRecord]

[ConvertRecord]
  Record Reader = JsonTreeReader
  Record Writer = AvroRecordSetWriter
  Schema Access Strategy = "Use Schema Name Property"
  Schema Name = events_schema_v1
  Relationships: success → [PutSnowflakeRecord]

[PutSnowflakeRecord]
  Database   = ANALYTICS
  Schema     = PUBLIC
  Table Name = EVENTS
  Insert Mode = APPEND
  Auto-create Table = false
  Relationships: success → [auto-terminated]
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. ListS3 polls the bucket every 30 seconds and emits one flow file per S3 object found, with attributes s3.bucket, s3.key, s3.length. The payload is empty at this stage — ListS3 only emits metadata.
  2. FetchS3Object reads the attributes, downloads the object's bytes, and writes them as the flow file's payload. Now every flow file is a full (payload, attributes) envelope.
  3. RouteOnAttribute inspects the s3.key attribute. Files matching prod/... go down the keep relationship; files matching test/... go to drop_test and are auto-terminated (dropped without further action). This is the typed routing primitive.
  4. ConvertRecord parses the NDJSON payload using a JSON record reader and re-emits the records as Avro using a registered schema (events_schema_v1). Records that fail schema validation go to failure (not wired here for brevity).
  5. PutSnowflakeRecord writes the Avro records into the EVENTS table via the Snowflake connector, using append mode. Each successful batch is acknowledged; failed records go to the connector's failure relationship.

Output (provenance lineage table).

flow_file_uuid s3.key route rows_written
ff-001 prod/...part-001.jsonl keep 12,400
ff-002 test/...part-002.jsonl drop_test 0 (dropped)
ff-003 prod/...part-003.jsonl keep 8,200

Rule of thumb. Every Openflow ingest flow has the same four-step shape: list/detect → fetch/extract → route/transform → publish/load. Drop in different head and tail processors for different sources and sinks.

Worked example — back-pressure in action

Detailed explanation. The most underrated NiFi feature is back-pressure. A common interview question — "what happens if the Snowflake load step gets slow?" The answer is "the queue between PutSnowflakeRecord and the upstream processor fills, and the upstream processor pauses; this propagates up the chain until the whole pipeline matches the slowest downstream." No buffers explode, no records get lost.

Question. A 5-processor flow runs at 10K flow files/sec on the head and 2K flow files/sec at the Snowflake sink. Trace what happens to the queues and the upstream processors after 60 seconds of imbalance.

Input.

Processor Max rate Queue max Queue policy
ListS3 10,000 ff/sec 10,000 ff back-pressure on
FetchS3Object 8,000 ff/sec 10,000 ff back-pressure on
RouteOnAttribute 9,000 ff/sec 10,000 ff back-pressure on
ConvertRecord 5,000 ff/sec 10,000 ff back-pressure on
PutSnowflakeRecord 2,000 ff/sec 10,000 ff back-pressure on

Code.

# Queue configuration (per connector between processors)
Back Pressure Object Threshold = 10000
Back Pressure Data Size Threshold = 1 GB
Flow File Expiration = 0 sec   # never expire
Prioritizers = FirstInFirstOutPrioritizer
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. At t=0, all processors are running at their own max rate. The queue between ConvertRecord and PutSnowflakeRecord fills fastest because the gap (5K in vs 2K out = +3K/sec) is largest.
  2. By t=3.3 sec the ConvertRecord → PutSnowflakeRecord queue hits 10,000 (its back-pressure threshold). ConvertRecord pauses immediately.
  3. With ConvertRecord paused, the RouteOnAttribute → ConvertRecord queue starts filling at 9K/sec (no drain). By t=4.4 sec it hits 10,000. RouteOnAttribute pauses.
  4. Back-pressure propagates upstream in the same way — FetchS3Object pauses next, then ListS3. After ~6-8 seconds the whole pipeline is paced at the slowest sink, 2K/sec.
  5. Meanwhile, the system has not lost any records. Every flow file is sitting safely in a queue with disk-backed persistence. When PutSnowflakeRecord drains, the chain resumes from the front.

Output (queue depths at steady state).

Queue Steady-state depth State
ListS3 → FetchS3Object 10,000 full (paused upstream)
FetchS3Object → RouteOnAttribute 10,000 full (paused upstream)
RouteOnAttribute → ConvertRecord 10,000 full (paused upstream)
ConvertRecord → PutSnowflakeRecord 10,000 full (sink is bottleneck)

Rule of thumb. The slowest downstream sets the rate of the whole flow. Watch for queues that sit at their back-pressure threshold for minutes — that's the bottleneck to scale up.

Worked example — provenance as audit trail

Detailed explanation. A compliance auditor asks: "for this row in the CUSTOMERS table, where did it come from, when was it ingested, what transformations were applied?" Without provenance, you would dig through logs across half a dozen systems. With Openflow provenance, you query a Snowflake table and get the full lineage in one query.

Question. Show the provenance trace for a single Salesforce customer record that was ingested into Snowflake via a 4-processor Openflow flow.

Input.

record_id source ingested_at target_table
sf-acc-0001 Salesforce.Account 2026-06-22 10:15:33 UTC ANALYTICS.CUSTOMERS

Code.

-- Provenance query — find every event for one flow file
SELECT
  event_id,
  event_type,
  event_time,
  processor_name,
  component_id,
  details
FROM OPENFLOW.PROVENANCE.EVENTS
WHERE flow_file_uuid = 'ff-2c8d-4f9a-8b1e-7a5c0f3e6d92'
ORDER BY event_time;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. The flow file is born at QuerySalesforce (event_type = RECEIVE). The provenance event records the source URL, query text, and timestamp.
  2. The flow file passes through ConvertRecord (event_type = CONTENT_MODIFIED). The provenance event records the schema applied and the size delta.
  3. RouteOnAttribute evaluates the routing expression (event_type = ATTRIBUTES_MODIFIED). The provenance event records the matched relationship.
  4. PutSnowflakeRecord emits the record to Snowflake (event_type = SEND). The provenance event records the target database, schema, table, and row count.
  5. The full chain — RECEIVE → CONTENT_MODIFIED → ATTRIBUTES_MODIFIED → SEND — is a single SQL query against the provenance table. End-to-end lineage in one row scan.

Output (provenance trace).

event_id event_type processor details
ev-1 RECEIVE QuerySalesforce SOQL: SELECT Id, Name, ... FROM Account
ev-2 CONTENT_MODIFIED ConvertRecord schema = sf_account_v3
ev-3 ATTRIBUTES_MODIFIED RouteOnAttribute route = keep
ev-4 SEND PutSnowflakeRecord ANALYTICS.CUSTOMERS row 47821

Rule of thumb. Treat provenance as your free lineage tool. A single Snowflake query against OPENFLOW.PROVENANCE.EVENTS answers every "where did this row come from?" audit question without a separate lineage product.

Senior interview question on NiFi parallelism inside Openflow

A senior interviewer might ask: "Your Openflow flow processes 50K events/sec from a Kafka topic. The PutSnowflakeRecord step is the bottleneck. How do you scale it without changing the rest of the pipeline?"

Solution Using concurrent tasks + runtime sizing + batching

# Diagnosis: PutSnowflakeRecord is single-threaded by default (1 concurrent task)
#            on a SMALL runtime; cannot keep up with 50K events/sec.

# Fix 1 — increase concurrent tasks on the bottleneck processor
[PutSnowflakeRecord]
  Concurrent Tasks = 8           # was 1; now uses 8 parallel threads
  Run Schedule = 0 sec           # always-running, not scheduled

# Fix 2 — increase runtime size for more CPU + memory
ALTER OPENFLOW RUNTIME aws_us_east_1_runtime SET SIZE = LARGE;

# Fix 3 — increase batch size on Snowflake writes (bigger transactions, fewer round-trips)
[PutSnowflakeRecord]
  Batch Size = 5000              # was 500; ~10x fewer Snowflake transactions

# Fix 4 — add a MergeContent step before the Snowflake write to combine small flow files
[MergeContent]
  Merge Strategy = Bin-Packing
  Min Number of Entries = 1000
  Max Bin Age = 30 sec
Enter fullscreen mode Exit fullscreen mode

Step-by-step trace.

Step Before fix After fix
Concurrent tasks on PutSnowflakeRecord 1 8
Runtime size SMALL LARGE
Batch size 500 5000
Merge before write none 1000 entries / 30 sec
Sink throughput ~2K/sec ~50K/sec
Queue depth upstream saturated drains within seconds

After the fix, the sink runs at 8 concurrent tasks × 5K-row batches and consumes the upstream queue at 50K/sec. The bottleneck moves upstream (or vanishes), the back-pressure releases, and the end-to-end throughput matches the source.

Output:

Metric Before After
End-to-end throughput ~2K events/sec ~50K events/sec
PutSnowflakeRecord queue depth saturated (10K) bounded < 1K
Snowflake transactions / sec ~4 ~10
Cost change base +1 runtime size step

Why this works — concept by concept:

  • Concurrent tasks scale a single processor — each processor has a Concurrent Tasks setting (default 1). Increasing it parallelises the processor on multiple threads inside the runtime. The bottleneck processor scales without redesigning the flow.
  • Runtime size controls the compute envelopeSIZE = SMALL/MEDIUM/LARGE/XLARGE sets the CPU and memory the runtime has. If you maxed out concurrent tasks and CPU is still pegged, increase the runtime size.
  • Batching amortises Snowflake transaction overhead — Snowflake writes are expensive per-call; bigger batches mean fewer transactions and lower per-row cost. The batch size knob is the highest-leverage cost lever in Openflow.
  • MergeContent eliminates small-file overhead — when upstream emits many tiny flow files (one per record), merging into 1K-row batches before the sink dramatically cuts overhead. Pair it with Max Bin Age so a slow stream doesn't stall.
  • Cost — runtime size step is linear in credits. Concurrent tasks are free within a runtime. Batch size is free. The cheapest scaling lever is batch size; the next is concurrent tasks; the most expensive is runtime size.

ETL
Topic — etl
NiFi flow-design problems

Practice →

SQL Topic — sql SQL problems for ingest validation

Practice →


3. Connector ecosystem + schema evolution

openflow connectors cover SaaS apps, databases, object stores, message queues — and Openflow ships drift policies that catalog tools cannot match

The mental model in one line: Openflow ships a first-party connector catalog (SaaS apps, operational databases with CDC, object stores, message queues) plus the entire OSS NiFi processor library, with schema evolution handled by configurable drift policies (add-column, type-widen, reject) and a custom-processor escape hatch via signed NAR bundles when nothing in the catalog fits. Once you internalise "catalog plus extensions plus drift policies," every openflow connectors and snowflake source connectors interview question becomes a deduction from that one set of primitives.

Visual diagram of Openflow connectors + schema evolution — top row of source connector icons (SaaS, DB CDC, S3, Kafka), middle a SchemaRegistry card with drift-policy chips (add-column, type-widen, reject), bottom a Snowflake target table with auto-add-column glyph, on a light PipeCode card.

The four source-connector classes.

  • SaaS app connectors. QuerySalesforce, QueryWorkday, QueryNetSuite, QueryHubSpot, QueryServiceNow, QuerySharePoint, plus generic InvokeHTTP for any REST API. Each ships OAuth handling, pagination, and incremental cursor management.
  • Database CDC connectors. CaptureChangePostgresql, CaptureChangeMySQL, CaptureChangeSQLServer, CaptureChangeOracle. Each reads the source DB's change log (WAL / binlog / CDC capture instance / LogMiner) and emits one flow file per change with op, before, after, lsn attributes.
  • Object store connectors. ListS3 + FetchS3Object for S3 (and the equivalents for GCS and Azure Blob). Pair with NiFi's record readers for Avro, Parquet, JSON, CSV.
  • Message queue connectors. ConsumeKafka, ConsumePulsar, ConsumeKinesis, ConsumeAzureEventHub. Each speaks the wire protocol natively and emits one flow file per message.

The sink-connector catalog.

  • PutSnowflakeRecord — the canonical sink. Loads records into a Snowflake table using the record API. Supports append, upsert (with merge keys), and full overwrite.
  • PutIceberg — write directly to Apache Iceberg tables (managed by Snowflake or external).
  • PutS3Object — write back to S3, useful for staging in external stages before a Snowpipe pickup.
  • External stages. For very high volumes, flows can stage files to S3 / GCS and trigger Snowpipe COPY — bridging the Openflow and Snowpipe ingest paths.

Schema evolution — three drift policies.

  • add-column. New columns in the source automatically ALTER the target table (ADD COLUMN col_x TYPE) and the new column is populated for subsequent rows. Old rows remain NULL.
  • type-widen. A column's type widens (e.g. INTBIGINT, VARCHAR(64)VARCHAR(256)) automatically. Narrowing is rejected.
  • reject. Any schema difference causes the flow file to fail. The failure relationship can route to a dead-letter queue for human review. The conservative default for regulated data.

Custom processors via NAR bundles.

  • A NAR (NiFi Archive) bundle packages your custom Java Processor, its dependencies, and a manifest. Sign it, upload it to your Snowflake account, and grant the runtime permission to load it.
  • The escape hatch. Use it when the source has no catalog connector (proprietary in-house APIs, niche SaaS apps, on-prem systems behind unusual auth).
  • Lifecycle. NAR bundles are versioned; you can upgrade a custom processor in place without redeploying the runtime. Test in a dev runtime first; promote via role-based publication.

Common interview probes on the connector ecosystem.

  • "Which CDC sources does Openflow support?" — Postgres, MySQL, SQL Server, Oracle (plus Snowflake itself via Streams).
  • "What is a NAR bundle?" — signed package of custom Java processors.
  • "How does schema drift work?" — three policies (add-column, type-widen, reject) per flow.
  • "Can Openflow write to Iceberg?" — yes, native PutIceberg processor.
  • "What is the relationship between Openflow and Snowpipe?" — Openflow can stage files to S3/GCS and trigger Snowpipe COPY, bridging the two ingest paths.

Worked example — Salesforce → Snowflake with schema drift handled

Detailed explanation. Salesforce schemas evolve constantly — admins add custom fields, change field types, rename columns. A robust QuerySalesforce → PutSnowflakeRecord flow must absorb these changes without breaking. Openflow's schema-drift policies are the cleanest answer in the market: pick add-column and the target table grows automatically.

Question. Build a flow that pulls Salesforce Account rows into a Snowflake ACCOUNTS table, set the drift policy to add-column, and trace what happens when a new custom field appears.

Input — Salesforce schema on day 1.

field type
Id string(18)
Name string(255)
Industry picklist
AnnualRevenue currency

Input — Salesforce schema on day 30 (new custom field added).

field type
Id string(18)
Name string(255)
Industry picklist
AnnualRevenue currency
Customer_Tier__c picklist

Code.

[QuerySalesforce]
  SOQL = SELECT Id, Name, Industry, AnnualRevenue, Customer_Tier__c FROM Account WHERE LastModifiedDate > ${last_sync}
  OAuth Connection = sf_prod_oauth
  Incremental Field = LastModifiedDate
  Schedule = 15 min

[ConvertRecord]
  Record Reader = SalesforceRecordReader
  Record Writer = SnowflakeRecordWriter
  Schema Access Strategy = "Infer from Source"
  Drift Policy = add-column            # the key knob

[PutSnowflakeRecord]
  Database   = ANALYTICS
  Schema     = PUBLIC
  Table Name = ACCOUNTS
  Insert Mode = MERGE
  Merge Key  = ID
  Drift Policy = add-column            # also set on the sink
  Auto-create Table = true             # creates if missing
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. On day 1, the Snowflake ACCOUNTS table has columns ID, NAME, INDUSTRY, ANNUAL_REVENUE. Flow runs every 15 min, merges new/changed accounts.
  2. On day 30, Salesforce admin adds Customer_Tier__c. The next QuerySalesforce run pulls rows with the new column.
  3. ConvertRecord notices the new field. Drift policy = add-column → the field is allowed and passed through with its source type.
  4. PutSnowflakeRecord receives a record with the new column. Drift policy = add-column → it issues ALTER TABLE ACCOUNTS ADD COLUMN CUSTOMER_TIER VARCHAR(255) before the merge.
  5. The merge then writes the new column for all rows in this batch. Older rows remain NULL until they are next updated and re-merged through the flow.

Output (target table schema after day 30).

column type populated
ID VARCHAR(18) all rows
NAME VARCHAR(255) all rows
INDUSTRY VARCHAR(255) all rows
ANNUAL_REVENUE NUMBER(18,2) all rows
CUSTOMER_TIER VARCHAR(255) day-30+ rows; older rows NULL

Rule of thumb. Use add-column for SaaS sources where admins routinely add fields. Use reject for regulated data where schema changes must go through human review. Never use add-column for a target that downstream consumers depend on without a schema-change broadcast.

Worked example — Postgres CDC into Snowflake with type widening

Detailed explanation. A Postgres CDC source captures every row change (insert, update, delete) and emits a flow file per change. A common production scenario: the source users table widens its score INT column to BIGINT after a DBA migration. The flow must absorb the type widening without breaking.

Question. Build a Postgres CDC flow into Snowflake that handles type-widening on the source side, and trace what happens when the source widens INTBIGINT.

Input.

source table change log target table
public.users (Postgres) WAL ANALYTICS.USERS (Snowflake)

Code.

[CaptureChangePostgreSQL]
  Database URL = jdbc:postgresql://prod-db.example.com/app
  Publication Name = openflow_pub
  Slot Name = openflow_slot
  Schedule = 0 sec   # continuous
  Relationships: success → [ConvertRecord], failure → [DeadLetter]

[ConvertRecord]
  Record Reader = JsonTreeReader
  Record Writer = SnowflakeRecordWriter
  Drift Policy = type-widen

[RouteOnAttribute]
  Property "insert": ${cdc.op:equals('I')}
  Property "update": ${cdc.op:equals('U')}
  Property "delete": ${cdc.op:equals('D')}

[PutSnowflakeRecord]  (one per route)
  insert → INSERT INTO USERS ...
  update → MERGE INTO USERS ...
  delete → DELETE FROM USERS WHERE ID = ${cdc.before.id}
  Drift Policy = type-widen
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. CaptureChangePostgreSQL connects to the WAL via a replication slot and emits one flow file per row change with attributes cdc.op (I/U/D), cdc.lsn, cdc.before, cdc.after.
  2. ConvertRecord parses the CDC payload and applies drift policy type-widen. When score widens from INT to BIGINT in a flow file, the converter accepts the new wider type.
  3. RouteOnAttribute splits the stream by operation type: inserts go to an insert sink, updates to a merge sink, deletes to a delete sink.
  4. Each PutSnowflakeRecord sink runs with type-widen. When the new BIGINT value arrives, the sink issues ALTER TABLE USERS ALTER COLUMN SCORE SET DATA TYPE NUMBER(19,0) before the write.
  5. The CDC stream continues uninterrupted; downstream queries see widened types without a manual migration.

Output (column widening trace).

event source type target type before DDL issued target type after
score INT → BIGINT BIGINT NUMBER(10,0) ALTER ... SET DATA TYPE NUMBER(19,0) NUMBER(19,0)
insert row BIGINT NUMBER(19,0) (none) NUMBER(19,0)

Rule of thumb. type-widen is safe for INT → BIGINT, FLOAT → DOUBLE, VARCHAR(N) → VARCHAR(2N). Narrowing is always rejected. Use type-widen for CDC sources where DBAs occasionally widen columns; pair with monitoring on the ALTER frequency.

Worked example — custom processor via NAR bundle

Detailed explanation. Your company has an in-house HR system with a bespoke REST API that no catalog connector covers. The escape hatch is to write a custom NiFi Processor in Java, package it as a NAR bundle, sign it, upload it to Snowflake, and grant your runtime permission to load it. Once loaded, your custom processor appears on the canvas alongside the catalog connectors.

Question. Write a minimal QueryAcmeHR custom processor that pulls employee records from an internal REST API, then show how to package and deploy it as a NAR bundle.

Input — internal API response shape.

field type
employee_id string
full_name string
department string
hire_date date

Code.

// QueryAcmeHR.java — custom NiFi processor
@Tags({"acme", "hr", "rest"})
@CapabilityDescription("Pulls employee records from the internal AcmeHR API")
public class QueryAcmeHR extends AbstractProcessor {

    public static final PropertyDescriptor API_URL = new PropertyDescriptor.Builder()
        .name("API URL").required(true).build();

    public static final PropertyDescriptor SINCE = new PropertyDescriptor.Builder()
        .name("Modified Since").required(false).build();

    @Override
    public void onTrigger(ProcessContext ctx, ProcessSession session) {
        String url = ctx.getProperty(API_URL).getValue();
        String since = ctx.getProperty(SINCE).evaluateAttributeExpressions().getValue();

        HttpResponse resp = http.get(url + "?since=" + since);
        for (Employee emp : resp.parse(Employee.class)) {
            FlowFile ff = session.create();
            ff = session.write(ff, out -> out.write(toJson(emp).getBytes()));
            ff = session.putAttribute(ff, "employee_id", emp.id);
            ff = session.putAttribute(ff, "mime.type", "application/json");
            session.transfer(ff, REL_SUCCESS);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
# Package as a NAR bundle
mvn clean package -Pnar
# Output: target/nifi-acme-hr-nar-1.0.0.nar

# Sign and upload to Snowflake
snow openflow nar upload \
  --runtime aws_us_east_1_runtime \
  --file target/nifi-acme-hr-nar-1.0.0.nar \
  --signature target/nifi-acme-hr-nar-1.0.0.nar.sig

# Grant the runtime permission to load it
GRANT USAGE ON NAR BUNDLE nifi_acme_hr_v1 TO RUNTIME aws_us_east_1_runtime;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. QueryAcmeHR extends AbstractProcessor and declares two properties (API URL, Modified Since). The onTrigger method runs each schedule tick — it calls the API, iterates the response, and emits one flow file per employee.
  2. Each flow file is created via session.create(), the payload is written via session.write(), attributes are set via session.putAttribute(), and the flow file is routed to REL_SUCCESS.
  3. mvn clean package -Pnar produces a .nar file — a special JAR with a manifest declaring the processor class. NAR bundles are isolated classloaders; dependencies do not leak to other processors.
  4. snow openflow nar upload uploads the signed NAR to your Snowflake account and registers it. The signature is verified before the runtime loads it.
  5. The GRANT USAGE ON NAR BUNDLE SQL grants the runtime permission to instantiate the processor. Once granted, QueryAcmeHR appears in the canvas processor list.

Output (canvas after upload).

processor name source available on canvas
QuerySalesforce first-party catalog yes
CaptureChangePostgreSQL first-party catalog yes
QueryAcmeHR custom NAR yes (after grant)

Rule of thumb. Custom processors are the escape hatch. Use them for sources that no catalog connector covers, sign every NAR, and treat them as versioned production code — they live in source control, ship via CI, and follow the same review process as your application code.

Senior interview question on schema-evolution policy

A senior interviewer might ask: "Your team runs 40 Openflow flows pulling from Salesforce, HubSpot, and 5 Postgres CDC streams. The product team adds 2-3 new fields per week. What schema-evolution policy do you set, and how do you keep downstream consumers safe?"

Solution Using per-environment drift policies + change broadcast

# Policy by environment
# - dev    : add-column (everything goes)
# - stage  : add-column + alert on every ALTER
# - prod   : reject + manual promotion via human-reviewed PR

[ConvertRecord/PutSnowflakeRecord]
  Drift Policy = ${env:equals('prod') ? 'reject' : 'add-column'}

# Drift-change alert via SNS / PagerDuty when an ALTER is detected
[RouteOnAttribute]
  Property "alter_detected": ${alter.column:notEmpty()}
  alter_detected → [InvokePagerDuty]

# Downstream consumer contract
# - publish a SCHEMA_REGISTRY table per flow
# - every consumer query joins to it; mismatches surface in CI
Enter fullscreen mode Exit fullscreen mode
-- Schema registry table — one row per (flow, column, version)
CREATE TABLE OPENFLOW.SCHEMA_REGISTRY (
  flow_name VARCHAR,
  column_name VARCHAR,
  column_type VARCHAR,
  added_at TIMESTAMP_NTZ,
  added_by_event VARCHAR
);

-- Every ALTER emitted by an Openflow flow inserts a row here.
-- Downstream dbt / Snowpark / BI tools join to it to know which columns exist
-- in each environment.
Enter fullscreen mode Exit fullscreen mode

Step-by-step trace.

Step Dev Stage Prod
New SF field detected accepted (add-column) accepted + alert rejected → dead letter
Target table altered yes (auto) yes (auto) + ticket created no (manual review)
Engineer reviews ticket n/a n/a reads ticket, opens PR
PR merges schema change n/a n/a manual ALTER in prod
Downstream consumers discover via registry discover via registry + alert discover via PR + registry

After the workflow is in place, dev/stage absorb every new field automatically while prod requires a human gate. Downstream consumers learn about new columns from the SCHEMA_REGISTRY table, not from broken queries.

Output:

Environment Policy Downstream safety
dev add-column n/a (sandbox)
stage add-column + alert engineers triage
prod reject + manual PR consumers see only reviewed changes

Why this works — concept by concept:

  • Policy varies by blast radius — dev is forgiving; prod is conservative. The same flow runs different policies in different environments because the cost of breakage differs by 100x.
  • Alerting on ALTER — every schema change in stage fires an alert; engineers see drift early and decide whether it should promote to prod. No silent prod schema changes.
  • Schema registry table — by writing every accepted schema change to a Snowflake table, you give downstream consumers a queryable contract. dbt jobs, BI queries, Snowpark jobs can all read this table at build time.
  • Reject + manual PR in prod — the conservative default for production is reject. The flow fails fast, the engineer sees the dead-letter, and a code change goes through review before the column lands in prod.
  • Cost — the policy mix is operationally cheap (drift policies are config, not code). The PR review step in prod is the only human cost, amortised across the safety it buys.

ETL
Topic — etl
Schema-evolution + connector problems

Practice →

ETL Topic — etl · medium Medium ETL design problems

Practice →


4. Openflow vs Fivetran vs Airbyte vs Snowpipe

openflow vs fivetran collapses to four sweet spots — Openflow for NiFi power, Fivetran for plug-and-play SaaS, Airbyte for OSS connectors, Snowpipe for cloud-storage auto-ingest

The mental model in one line: the four ingest tools each have a non-overlapping sweet spot — Openflow wins on NiFi power and custom processors, Fivetran wins on plug-and-play SaaS with predictable per-MAR pricing, Airbyte wins on OSS connector breadth with self-host control, Snowpipe wins on auto-ingest from cloud storage at very high volume. Once you internalise those four sweet spots, every openflow vs fivetran interview surface collapses to "which sweet spot does this source fall into?"

Visual diagram of Openflow vs Fivetran vs Airbyte vs Snowpipe — four medallion cards each with a one-line sweet-spot label and a use-case chip, on a light PipeCode card.

The four sweet spots in one line each.

  • Openflow. Visual flow + NiFi power + Snowflake-native + custom processors. Wins when you need in-flight transform, custom routing, CDC across many DB engines, or custom connectors.
  • Fivetran. Plug-and-play SaaS. Wins when the source is a popular SaaS app, you only need raw extract, and per-MAR pricing fits your budget.
  • Airbyte. OSS connectors + dbt-ish workflow. Wins when you want connector breadth, self-host control, and a CDK to write your own connectors in Python.
  • Snowpipe. Auto-ingest from cloud storage. Wins when files land in S3/GCS/Azure Blob continuously and you want hands-off COPY with the lowest possible per-row cost.

The DSL split — same goal, different shape.

  • Openflow. Visual flow canvas, NiFi processors, Java NAR bundle escape hatch. Think "I wire processors and configure properties."
  • Fivetran. UI-driven connector setup, no DSL, no code. Think "I OAuth a source and pick a destination."
  • Airbyte. YAML/JSON connector specs + Python CDK. Think "I configure a connector or write one in Python."
  • Snowpipe. SQL CREATE PIPE + COPY INTO. Think "I declare a pipe and Snowflake watches a stage for files."

Where each tool struggles.

  • Openflow. Cost at very high volume of small flow files (Snowpipe wins). SaaS-only setups where Fivetran's per-MAR pricing dominates. Engineering team needs NiFi familiarity.
  • Fivetran. No in-flight transform. No custom connectors. Per-MAR pricing hostile at very high MAR counts.
  • Airbyte. Self-host operational burden (OSS) or Airbyte Cloud cost. Connector quality varies — the long-tail OSS connectors are less reliable than first-party ones.
  • Snowpipe. Only handles files in cloud storage. No SaaS, no DB CDC, no in-flight transform.

The 2026 reality — what changed.

  • Openflow GA on all clouds. The "is it production ready?" question is settled. The first-party connector catalog covers ~50 sources.
  • Fivetran connector library. ~600 connectors as of 2026, covering most popular SaaS apps. Still no in-flight transform.
  • Airbyte 1.0. Stable Python CDK, dbt integration, and a larger contributor community.
  • Snowpipe Streaming. Lower-latency ingest from cloud-storage; broadens Snowpipe's reach toward sub-minute scenarios.

What interviewers listen for.

  • Do you say "these tools cover non-overlapping sweet spots" in the first sentence? — senior signal.
  • Do you mention in-flight transform as the Openflow wedge unprompted? — senior signal.
  • Do you describe per-MAR vs per-flow-file vs per-COPY pricing differences? — required answer.
  • Do you push back on "Openflow replaces Fivetran" with "they target different operational shapes"? — senior signal.

Worked example — decision matrix on 6 real sources

Detailed explanation. The cleanest way to make the comparison concrete is to walk through a realistic portfolio of 6 sources and pick the right tool for each. The answer is rarely one tool — it's usually a portfolio.

Question. For each of the 6 sources below, pick the right ingest tool and explain why.

Input (6-source portfolio).

Source Type Volume Transform needed Custom?
Salesforce SaaS 1M MAR none no
HubSpot SaaS 0.4M MAR none no
Postgres production DB CDC 5M events/day route by op no
Internal HR system custom REST 100K/day enrich + route yes
S3 click events cloud drops 200M files/day none no
Internal Iceberg lake Iceberg 10M rows/day dedup + route no

Code.

# Tool picks
Salesforce            → Fivetran (per-MAR pricing wins on SaaS, no transform)
HubSpot               → Fivetran (same logic)
Postgres CDC          → Openflow (NiFi CDC + routing in-flight)
Internal HR system    → Openflow (custom NAR processor)
S3 click events       → Snowpipe (volume + per-COPY pricing wins)
Internal Iceberg lake → Openflow (PutIceberg + dedup processor)
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. Salesforce and HubSpot are popular SaaS apps with no in-flight transform required. Fivetran owns the connector, the schema, and the runtime; per-MAR pricing is competitive at 1.4M total MAR.
  2. Postgres CDC needs operation-type routing (insert / update / delete to different sinks). Openflow's CaptureChangePostgreSQL + RouteOnAttribute handles this natively; Fivetran cannot route in-flight.
  3. The internal HR system has no catalog connector anywhere. Openflow's custom NAR processor is the only option that keeps the pipeline on a single platform.
  4. The S3 click events are 200M files/day. Snowpipe's per-COPY pricing wins by an order of magnitude over any per-flow-file model. No transform needed → no reason to use Openflow.
  5. The Iceberg lake needs dedup + routing before write. Openflow's PutIceberg + dedup processor handles this; Snowpipe cannot do dedup pre-write.

Output (final portfolio).

Source Tool Reason
Salesforce Fivetran SaaS + no transform + per-MAR competitive
HubSpot Fivetran SaaS + no transform
Postgres CDC Openflow NiFi CDC + op routing
Internal HR system Openflow custom NAR processor
S3 click events Snowpipe volume + per-COPY pricing
Internal Iceberg lake Openflow PutIceberg + dedup pre-write

Rule of thumb. Always design the portfolio first. Pick the right tool per source, then optimise across the portfolio (e.g. consolidating Openflow flows on a single runtime to amortise its base cost).

Worked example — when to migrate Fivetran to Openflow

Detailed explanation. A common 2026 question: "you have 30 Fivetran connectors costing $200K/year. Should you migrate to Openflow?" The answer is: only the ones where Openflow's NiFi power buys you something Fivetran cannot do. Migrating raw-extract SaaS connectors is rarely worth the engineering cost.

Question. Decide which of these 5 Fivetran connectors to migrate to Openflow.

Input.

Fivetran connector MAR / month Engineering pain In-flight transform desired?
Salesforce 1M none no
Stripe 0.4M none no
Workday 0.2M schema breaks 1x/month no
ServiceNow 0.1M needs custom field routing yes
Internal API (via Fivetran HTTP) 0.05M flaky, no real connector yes

Code.

# Migration triage
Salesforce  → keep on Fivetran (no transform, no pain)
Stripe      → keep on Fivetran (same)
Workday     → keep on Fivetran for now; reconsider if pain worsens
ServiceNow  → migrate to Openflow (custom field routing in-flight)
Internal    → migrate to Openflow (write custom NAR; lose Fivetran HTTP fragility)
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. Salesforce and Stripe are working. No transform, no pain → no reason to migrate. The engineering cost (build, test, ship) is real; Fivetran's per-MAR is acceptable.
  2. Workday breaks once a month but Fivetran owns the fix. Migrating would put schema repair on your team. Keep on Fivetran unless the pain escalates.
  3. ServiceNow needs custom field routing — sending some fields to one table and others to another. Fivetran cannot do this in-flight. Migrate to Openflow.
  4. The internal API runs through Fivetran's generic HTTP connector but is flaky. A custom NAR processor with proper error handling and retry semantics is the durable fix. Migrate.
  5. The result: 3 of 5 stay on Fivetran, 2 of 5 move to Openflow. Total cost slightly drops; engineering pain on the moved connectors drops dramatically.

Output.

Connector Move? Year-1 cost change
Salesforce no $0
Stripe no $0
Workday no $0
ServiceNow yes -$15K (saved per-MAR) + $10K (eng time) = -$5K
Internal yes -$8K (saved per-MAR) + $20K (eng time, year 1) = +$12K

Rule of thumb. Migrate Fivetran → Openflow only when one of two things is true: you need in-flight transform / routing, or you need a custom connector. Migrating raw-extract SaaS for cost savings rarely breaks even in year 1.

Worked example — bridging Openflow and Snowpipe

Detailed explanation. Openflow and Snowpipe are not mutually exclusive — the senior answer often bridges them. Openflow handles the SaaS / DB / custom side; Snowpipe handles the cloud-storage side; an Openflow flow that stages files to S3 hands them to Snowpipe for the final COPY.

Question. Design a flow where Openflow does the in-flight transform and stages files to S3, then Snowpipe COPYs them into Snowflake at volume.

Input.

Source Pre-transform Stage Final load
Salesforce + Postgres CDC + Internal HR Openflow S3 Snowpipe

Code.

# Openflow flow — pull from sources, transform, stage to S3
[QuerySalesforce + CaptureChangePostgreSQL + QueryAcmeHR]
  → [ConvertRecord]    Drift Policy = add-column
  → [JoltTransformJSON]                          # in-flight enrichment
  → [MergeContent]     Min Entries = 5000        # batch up
  → [PutS3Object]      Bucket = events-staging, Prefix = ${date}/${flow}/
Enter fullscreen mode Exit fullscreen mode
-- Snowpipe — auto-ingest from the staging bucket
CREATE PIPE openflow_staging_pipe
  AUTO_INGEST = TRUE
  AS COPY INTO ANALYTICS.EVENTS FROM @events_staging_stage
     FILE_FORMAT = (TYPE = AVRO);

-- SQS notification wired in the AWS console → Snowflake picks up files within ~1 min.
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. Openflow does the work it's best at — pulling from multiple sources, applying in-flight transforms, batching with MergeContent. The output is a stream of well-formed Avro files in S3.
  2. PutS3Object writes those files to a staging prefix in S3 — versioned, partitioned by date and flow name. Openflow's role ends here.
  3. Snowpipe's role begins here. The CREATE PIPE ... AUTO_INGEST = TRUE declaration tells Snowflake to watch the stage for new files via SQS notifications.
  4. Each new file in S3 triggers a COPY INTO micro-execution. Snowpipe owns the file detection, the COPY, the credit billing.
  5. Net effect: Openflow handles the complex part (sources + transforms); Snowpipe handles the cheap-at-volume part (final COPY). Each tool runs in its sweet spot.

Output.

Stage Tool Cost shape
Source extraction Openflow per-flow-file credits
In-flight transform Openflow per-flow-file credits
S3 staging Openflow → S3 S3 PUT cost
Final COPY into Snowflake Snowpipe per-COPY credits

Rule of thumb. When both openflow vs fivetran and snowpipe look like they could work, design the handoff — let Openflow do the transform, hand to Snowpipe for the high-volume COPY. Each runs in its sweet spot, and the cost stays in line.

Senior interview question on ingest-tool selection

A senior interviewer might frame this as: "You join a team running 50 Fivetran connectors and 5 Snowpipes. Leadership wants you to evaluate Openflow. Walk me through how you'd present the trade-off and what migration plan you'd recommend."

Solution Using a 5-question selection framework + portfolio plan

Ingest tool selection — Openflow vs Fivetran vs Airbyte vs Snowpipe

Q1 Source kind   → SaaS only? Fivetran/Airbyte. DB/CDC/custom? Openflow. Cloud storage? Snowpipe.
Q2 Transform     → none needed? catalog wins. needed? Openflow.
Q3 Custom needed → no? catalog wins. yes? Openflow.
Q4 Volume        → > 100M files/day cloud storage? Snowpipe. otherwise compare.
Q5 Ops capacity  → no platform team? catalog wins. have one? Openflow scales further.

Tool-specific trade-offs
------------------------
Openflow
  + Visual flow + NiFi power + Snowflake-native + custom processors
  + In-flight transform / routing
  + One platform across many source classes
  − Cost at very low volume can lose to Fivetran
  − Engineering team needs NiFi familiarity

Fivetran
  + Plug-and-play, no engineering
  + ~600 SaaS connectors
  + Predictable per-MAR pricing
  − No in-flight transform
  − No custom connector
  − Hostile per-MAR pricing at very high counts

Airbyte
  + OSS connector breadth, Python CDK
  + Self-host control
  + dbt-ish workflow integrations
  − Self-host operational burden (OSS)
  − Connector quality varies on the long tail

Snowpipe
  + Cheapest per-COPY at high volume
  + Native Snowflake, zero infra
  + Auto-ingest via SNS/SQS
  − Cloud storage only
  − No transform
Enter fullscreen mode Exit fullscreen mode

Step-by-step trace.

Q1 source Q2 transform Q3 custom Q4 volume Q5 ops Picked
SaaS only none no medium small team Fivetran
DB CDC route by op no medium platform team Openflow
Cloud storage none no 200M/day any Snowpipe
Custom REST enrich yes low platform team Openflow

After the 5-question pass, the portfolio plan picks itself: keep Fivetran for raw SaaS, move DB CDC + custom REST + complex routing flows to Openflow, keep Snowpipe for high-volume cloud-storage drops.

Output:

Tool Keep / Move Sources
Fivetran keep ~40 of 50 popular SaaS, raw extract
Openflow new (~15 flows) CDC, custom, complex routing, Iceberg
Airbyte n/a not in current portfolio
Snowpipe keep all 5 high-volume cloud-storage drops

Why this works — concept by concept:

  • 5 questions in order — Q1 (source kind) is the highest-leverage question. Once you know SaaS vs DB vs custom vs cloud-storage, the answer set narrows by 75%.
  • Tool-specific trade-offs — memorising each tool's 3 strengths and 2-3 hard constraints lets you reason about edge cases without re-deriving the whole framework.
  • Portfolio thinking — the right answer is rarely one tool. The portfolio plan keeps existing Fivetran/Snowpipe investments and adds Openflow for the sources that justify it.
  • Cost vs engineering effort — every migration has a non-trivial engineering cost. Migrate only when in-flight transform / custom connector / pain breaks the break-even math.
  • Cost — engineering migration is the dominant cost; tool credits are typically the second-largest. Plan the migration in waves (CDC first, custom second, raw extract never).

ETL
Topic — etl
Ingest tool-selection problems

Practice →

SQL Topic — sql SQL problems for ingest analytics

Practice →


5. Production patterns + governance

Production Openflow means one Connect runtime per env, role-based publication, back-pressure monitoring, and a credit-cost dashboard — the platform discipline that separates a demo from a shipped pipeline

The mental model in one line: production Openflow is one Connect runtime per env per cloud-region, flows owned by roles and promoted through publication gates, every flow file monitored end-to-end with back-pressure alerts, and credit cost tracked per runtime + per flow file in a dashboard you watch weekly; that operational discipline turns Openflow from a flow-canvas demo into a shipped data platform. Once you internalise those four pillars — runtime, governance, monitoring, cost — every senior openflow runtime interview question becomes a deduction from production realities.

Visual diagram of Openflow in production — left a runtime-deploy card with cloud/region chips; centre a governed-flow card with role-based publication; right a back-pressure + monitoring card; bottom a cost monitor strip, on a light PipeCode card.

The four production pillars.

  • Runtime topology. One Connect runtime per env per cloud + region. Production runs on its own runtime; dev and stage share a smaller one. Multi-region runtimes give you network reach plus disaster-recovery isolation.
  • Governance. Every flow has a publisher role and a set of reader roles. OPENFLOW_ADMIN_PROD publishes; OPENFLOW_DEVELOPER_PROD can edit drafts; OPENFLOW_VIEWER_PROD can read. The publish step is a hard gate — only _ADMIN_ roles can promote.
  • Monitoring. Three metric families: flow-file throughput (events/sec, total flow files, queue depths), back-pressure (which queues are saturated), retry / failure rate (per-relationship counts). Wire each to your alerting stack.
  • Cost model. Two axes: per-runtime credits (always-on or auto-suspended compute) + per-flow-file credits (the variable cost). Build a weekly dashboard that tracks both.

The DSL split — same flow definition, different roles.

  • Developer. Designs the flow in dev, tests against dev sources, commits to a flow definition.
  • Reviewer. Reads the flow diff, runs it against stage sources, signs off.
  • Admin. Publishes the flow to the prod runtime — a one-way gate that requires explicit role grant.
  • Viewer. Reads the flow definition and runtime metrics; cannot edit or publish.

Back-pressure + retry semantics.

  • Back-pressure is automatic. Full queues pause upstream processors. Watch for any queue that sits at threshold for > 5 minutes.
  • Retries on failure. Each processor's failure relationship can route back to itself (with penalisation) for transient failures, or to a dead-letter queue (DLQ) for permanent ones.
  • Exactly-once-ish. Openflow's transactional sink to Snowflake (PutSnowflakeRecord with Use Transaction = true) gives you exactly-once for the Snowflake write. Upstream idempotence depends on the source connector.

Cost model — per-runtime + per-flow-file.

  • Per-runtime cost. Fixed credits per hour the runtime is running. AUTO_SUSPEND = 600 lets it sleep after 10 minutes of idle, dramatically cutting cost on infrequent flows.
  • Per-flow-file cost. Variable credits per flow file processed. Bigger batches = fewer flow files = lower variable cost.
  • The cost dashboard. A weekly Snowflake query against OPENFLOW.USAGE tells you which flows / runtimes are burning the most credits.

Common interview probes on production.

  • "How do you isolate prod from dev?" — separate runtimes + separate role grants.
  • "How do you monitor an Openflow flow?" — flow-file metrics + back-pressure + failure-relationship counts.
  • "What is the cost model?" — per-runtime + per-flow-file credits.
  • "How do you do exactly-once?" — transactional sink + idempotent upstream source connector.
  • "How do you upgrade a flow?" — edit in dev, promote through stage, admin publishes to prod.

Worked example — deploying a Connect runtime

Detailed explanation. Deploying a Connect runtime is a 4-step SQL exercise: declare the runtime, set sizing and auto-suspend, grant runtime usage to roles, and verify the network reach. Once it exists, every flow you publish to it inherits its compute, network, and governance properties.

Question. Deploy a production Connect runtime on AWS us-east-1 sized MEDIUM with AUTO_SUSPEND = 600, then grant developer and viewer roles.

Input.

Property Value
cloud AWS
region us-east-1
size MEDIUM
auto_suspend 600 sec
environment prod

Code.

-- 1) Create the runtime
CREATE OPENFLOW RUNTIME prod_aws_us_east_1
  CLOUD = AWS
  REGION = 'us-east-1'
  SIZE = MEDIUM
  AUTO_SUSPEND = 600
  COMMENT = 'Production ingest runtime - us-east-1';

-- 2) Verify it exists
SHOW OPENFLOW RUNTIMES LIKE 'prod_aws_us_east_1';

-- 3) Grant developer + viewer + admin
GRANT USAGE ON RUNTIME prod_aws_us_east_1 TO ROLE openflow_admin_prod;
GRANT USAGE ON RUNTIME prod_aws_us_east_1 TO ROLE openflow_developer_prod;
GRANT USAGE ON RUNTIME prod_aws_us_east_1 TO ROLE openflow_viewer_prod;

-- 4) Get the runtime's stable egress IP for source-system allowlisting
SELECT
  runtime_name,
  egress_ip_addresses
FROM OPENFLOW.RUNTIMES
WHERE runtime_name = 'PROD_AWS_US_EAST_1';
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. CREATE OPENFLOW RUNTIME declares a managed NiFi cluster. Snowflake provisions the underlying compute, ZooKeeper, and state storage; you never see them.
  2. SIZE = MEDIUM allocates roughly 2x the vCPU and memory of SMALL. You can ALTER ... SET SIZE = LARGE later without downtime.
  3. AUTO_SUSPEND = 600 puts the runtime to sleep after 10 minutes of idle. Flows scheduled less than every 10 minutes wake it; very rare flows pay only for the run-time minutes.
  4. The three GRANT USAGE statements establish role-based access: admins can publish, developers can edit, viewers can read. No cross-environment access (you'd grant separate roles per env).
  5. The stable egress IP (or CIDR) is queryable via OPENFLOW.RUNTIMES. Send it to the operational teams that own the source systems for allowlist entries on Salesforce / Postgres / etc.

Output.

runtime_name size auto_suspend egress_ip
PROD_AWS_US_EAST_1 MEDIUM 600 52.x.x.x/29

Rule of thumb. Deploy one runtime per env per cloud + region. Use AUTO_SUSPEND = 600 unless flows run at least every 10 minutes. Capture the stable egress IP early — source-system allowlist changes take weeks at large companies.

Worked example — role-based flow publication

Detailed explanation. A common production pattern: developers should be able to edit and test flow definitions but only an admin role can promote them to prod. Openflow's role-based publication enforces this without external CI/CD glue.

Question. Set up role-based publication so that developers can edit but only admins can publish a flow.

Input.

Role Can edit drafts Can publish Can read
openflow_admin_prod yes yes yes
openflow_developer_prod yes no yes
openflow_viewer_prod no no yes

Code.

-- 1) Per-role permissions on flows
GRANT CREATE FLOW ON RUNTIME prod_aws_us_east_1 TO ROLE openflow_developer_prod;
GRANT MODIFY FLOW ON RUNTIME prod_aws_us_east_1 TO ROLE openflow_developer_prod;
GRANT PUBLISH FLOW ON RUNTIME prod_aws_us_east_1 TO ROLE openflow_admin_prod;
GRANT READ FLOW   ON RUNTIME prod_aws_us_east_1 TO ROLE openflow_viewer_prod;

-- 2) Developer creates a draft
USE ROLE openflow_developer_prod;
CREATE FLOW sf_accounts AS
  /* flow definition - QuerySalesforce -> ConvertRecord -> PutSnowflakeRecord */;

-- 3) Developer cannot publish
USE ROLE openflow_developer_prod;
ALTER FLOW sf_accounts SET STATUS = 'PUBLISHED';
-- ERROR: insufficient privileges -- requires PUBLISH FLOW

-- 4) Admin publishes
USE ROLE openflow_admin_prod;
ALTER FLOW sf_accounts SET STATUS = 'PUBLISHED';
-- OK
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. GRANT CREATE FLOW and GRANT MODIFY FLOW let developers create and edit draft flows. GRANT PUBLISH FLOW is admin-only — it is the promotion gate.
  2. The developer creates the draft flow definition. Snowflake stores it as a versioned object inside the runtime.
  3. When the developer tries to publish (set status to PUBLISHED), Snowflake's RBAC engine rejects the call. The developer can only ship via an admin.
  4. The admin reviews the flow definition (diff against the prior version, comments, tests on a stage runtime) and runs ALTER FLOW ... SET STATUS = 'PUBLISHED'. The flow goes live.
  5. Net effect: production publications go through an explicit admin gate without external CI/CD scaffolding. Audit log captures who published what when.

Output.

flow author publisher status
sf_accounts jane@acme.com (developer) sara@acme.com (admin) PUBLISHED

Rule of thumb. Always separate developer and admin roles in production. The publish-gate prevents accidental deploys; the audit trail satisfies compliance reviewers; the explicit promotion creates a natural review checkpoint.

Worked example — monitoring + back-pressure alerts

Detailed explanation. Production flows fail. Sources go down, target tables get locked, queues fill. Monitoring is how you find out before the business does. Three metric families are non-negotiable: throughput, back-pressure, failure rate.

Question. Build a monitoring query set that alerts when (a) any queue is at back-pressure for > 5 minutes, (b) any flow's failure rate is > 1%, or (c) total flow files drop > 50% vs prior hour.

Input — what we monitor.

Metric family Source table Alert threshold
Queue depth OPENFLOW.METRICS.QUEUE_DEPTH 95% of max for 5 min
Failure rate OPENFLOW.METRICS.PROCESSOR_FAILURES > 1% for 10 min
Throughput OPENFLOW.METRICS.FLOW_FILES_PROCESSED < 50% vs prior hour

Code.

-- (a) Queue back-pressure alert
SELECT
  flow_name,
  connection_name,
  AVG(queue_depth_pct) AS avg_depth_pct
FROM OPENFLOW.METRICS.QUEUE_DEPTH
WHERE measured_at > DATEADD(minute, -5, CURRENT_TIMESTAMP())
GROUP BY 1, 2
HAVING AVG(queue_depth_pct) > 95;

-- (b) Failure-rate alert
SELECT
  flow_name,
  processor_name,
  SUM(failure_count) / NULLIF(SUM(success_count) + SUM(failure_count), 0) AS failure_rate
FROM OPENFLOW.METRICS.PROCESSOR_FAILURES
WHERE measured_at > DATEADD(minute, -10, CURRENT_TIMESTAMP())
GROUP BY 1, 2
HAVING failure_rate > 0.01;

-- (c) Throughput-drop alert
WITH hourly AS (
  SELECT
    flow_name,
    DATE_TRUNC('hour', measured_at) AS hr,
    SUM(flow_files) AS ff
  FROM OPENFLOW.METRICS.FLOW_FILES_PROCESSED
  GROUP BY 1, 2
)
SELECT
  curr.flow_name,
  curr.ff AS curr_hour_ff,
  prev.ff AS prev_hour_ff,
  curr.ff::FLOAT / NULLIF(prev.ff, 0) AS ratio
FROM hourly curr
JOIN hourly prev
  ON curr.flow_name = prev.flow_name
 AND curr.hr = DATEADD(hour, 1, prev.hr)
WHERE curr.hr = DATE_TRUNC('hour', DATEADD(hour, -1, CURRENT_TIMESTAMP()))
  AND curr.ff::FLOAT / NULLIF(prev.ff, 0) < 0.5;
Enter fullscreen mode Exit fullscreen mode

Step-by-step explanation.

  1. The queue-depth alert (a) reads from OPENFLOW.METRICS.QUEUE_DEPTH — a managed metrics table Snowflake populates from the runtime. Any queue averaging > 95% full for 5 minutes is a back-pressure flag.
  2. The failure-rate alert (b) computes a rolling 10-minute failure ratio per processor. A persistent > 1% rate usually means a credential rotation, a target-table lock, or a schema mismatch.
  3. The throughput-drop alert (c) joins the current hour to the prior hour and flags any flow whose throughput dropped by more than half. Catches stuck sources before the alerting on (a) or (b) fires.
  4. Wire each query to your existing alerting stack (Snowflake task → external function → PagerDuty / Slack). Run on a 1-min schedule.
  5. Net effect: you have a 3-axis safety net (back-pressure + failure + throughput) that detects ~95% of production incidents in the first 5 minutes.

Output (sample alert payload).

flow_name processor metric value threshold
sf_accounts PutSnowflakeRecord failure_rate 0.04 0.01

Rule of thumb. Don't roll your own metrics from logs. Use the managed OPENFLOW.METRICS.* tables Snowflake exposes — they are kept in sync with the runtime and survive runtime restarts.

Senior interview question on production Openflow

A senior interviewer might ask: "Your CFO sees a 30% jump in Openflow credit cost month-over-month and asks you to investigate. Walk me through how you'd diagnose and what changes you'd make."

Solution Using credit-cost diagnosis + flow-level optimisation

-- 1) Top-cost flows in the current month
SELECT
  flow_name,
  runtime_name,
  SUM(credits_used) AS month_credits,
  SUM(flow_files_processed) AS month_flow_files,
  SUM(credits_used) / NULLIF(SUM(flow_files_processed), 0) AS credits_per_flow_file
FROM OPENFLOW.USAGE
WHERE DATE_TRUNC('month', measured_at) = DATE_TRUNC('month', CURRENT_DATE())
GROUP BY 1, 2
ORDER BY month_credits DESC
LIMIT 20;

-- 2) Per-runtime always-on credits (the fixed cost)
SELECT
  runtime_name,
  SUM(uptime_credits) AS uptime_credits,
  AVG(active_pct) AS avg_active_pct
FROM OPENFLOW.RUNTIME_USAGE
WHERE DATE_TRUNC('month', measured_at) = DATE_TRUNC('month', CURRENT_DATE())
GROUP BY 1
ORDER BY uptime_credits DESC;

-- 3) Identify levers
-- - High credits_per_flow_file → batch upstream (MergeContent)
-- - Low avg_active_pct + high uptime_credits → set AUTO_SUSPEND
-- - Spike in one flow → check if drift policy triggered a backfill
Enter fullscreen mode Exit fullscreen mode

Step-by-step trace.

Step Finding Fix
1 flow s3_landing running 1B flow files/mo, $80K credits replace with Snowpipe
2 runtime prod_eu_west_1 8% active, $12K uptime set AUTO_SUSPEND = 600
3 flow sf_accounts credit-per-ff jumped 4x MergeContent batch increased
4 runtime prod_us_east_1 90% active, $40K uptime keep (active, justified)
5 total month-over-month delta explained -$50K projected next month

After applying the fixes — moving the high-volume S3 ingest to Snowpipe, setting auto-suspend on the lightly-used EU runtime, batching small flows — the projected next-month credit cost drops by ~$50K (the 30% jump reverses).

Output:

Lever Estimated savings
Move s3_landing to Snowpipe $35K / month
Set AUTO_SUSPEND on EU runtime $10K / month
Batch small SaaS flows via MergeContent $5K / month
Total $50K / month

Why this works — concept by concept:

  • Cost is two-axis — per-runtime + per-flow-file. Diagnose each separately. High runtime cost is solved by sizing + auto-suspend; high per-flow-file cost is solved by batching + the right tool.
  • The right-tool rule — high-volume cloud-storage ingest belongs on Snowpipe, not Openflow. Always look for a sweet-spot mismatch on the most expensive flow first.
  • MergeContent for small files — small flow files burn per-flow-file credits. Merge 1K records into one flow file and the credit cost drops 1000x for the same throughput.
  • AUTO_SUSPEND for idle runtimes — flows that run hourly or less should not pay for always-on compute. Set AUTO_SUSPEND = 600 and the runtime sleeps 90%+ of the time.
  • Cost — diagnosis is O(flows) and run once a month. Fixes are O(flows-with-issues). The dashboard is permanent — keep it as a weekly review.

ETL
Topic — etl
Openflow production-operations problems

Practice →

ETL
Topic — etl · medium
Medium ETL platform problems

Practice →


Cheat sheet — Openflow recipes

  • Runtime deploy in 4 steps. CREATE OPENFLOW RUNTIME ... CLOUD=AWS REGION='us-east-1' SIZE=MEDIUM AUTO_SUSPEND=600;SHOW OPENFLOW RUNTIMES;GRANT USAGE ON RUNTIME ... TO ROLE openflow_developer_prod; → query OPENFLOW.RUNTIMES.egress_ip_addresses and ship to source-system owners for allowlist.
  • The canonical 5-processor S3 → Snowflake flow. ListS3FetchS3ObjectRouteOnAttributeConvertRecordPutSnowflakeRecord. Auto-terminate drop_* relationships; route failure to a dead-letter queue.
  • Salesforce → Snowflake daily. QuerySalesforce (with Incremental Field = LastModifiedDate) → ConvertRecord (Drift Policy = add-column) → PutSnowflakeRecord (Insert Mode = MERGE, Merge Key = ID).
  • Postgres CDC fanout. CaptureChangePostgreSQLRouteOnAttribute (by cdc.op = I/U/D) → three PutSnowflakeRecord sinks (insert / merge / delete). Drift Policy = type-widen.
  • Schema-drift policy by env. Dev = add-column; stage = add-column + alert on every ALTER; prod = reject + manual PR for promotion.
  • Custom processor in 3 steps. Write Java Processor, package via mvn clean package -Pnar, upload via snow openflow nar upload --file ....nar, then GRANT USAGE ON NAR BUNDLE ... TO RUNTIME ....
  • Back-pressure scaling. Bottleneck = highest Concurrent Tasks; sink = highest Batch Size; persistent saturation = ALTER OPENFLOW RUNTIME SET SIZE = LARGE.
  • MergeContent for small files. Min Number of Entries = 1000, Max Bin Age = 30 sec. Drops per-flow-file credit cost by ~1000x for the same throughput.
  • Role separation. _ADMIN_ publishes only; _DEVELOPER_ edits drafts; _VIEWER_ reads metrics. Per-env (_DEV, _STAGE, _PROD) suffix; no cross-env grants.
  • Monitoring trifecta. (a) OPENFLOW.METRICS.QUEUE_DEPTH > 95% for 5 min → back-pressure; (b) failure_count / total > 1% for 10 min → fail; (c) curr_hour_ff / prev_hour_ff < 0.5 → throughput drop. Wire to PagerDuty.
  • Provenance lineage. SELECT * FROM OPENFLOW.PROVENANCE.EVENTS WHERE flow_file_uuid = '...' returns the full processor-by-processor lineage for any flow file.
  • Cost dashboard. Weekly query against OPENFLOW.USAGE: top-cost flows + per-runtime uptime + credits-per-flow-file ratio. Diagnose with the right-tool rule (high-volume S3 → Snowpipe), AUTO_SUSPEND for idle runtimes, and MergeContent for small files.
  • Openflow ↔ Snowpipe bridge. Openflow ends with PutS3Object into a staging bucket; Snowpipe owns the final COPY INTO from that bucket. Each tool runs in its sweet spot.
  • Connector cheat. SaaS = QuerySalesforce / QueryHubSpot / QueryWorkday. CDC = CaptureChange{Postgres,MySQL,SQLServer,Oracle}. Files = ListS3 + FetchS3Object. Streams = ConsumeKafka / ConsumePulsar / ConsumeKinesis. Custom = NAR bundle.
  • Exactly-once recipe. Source connector with idempotent extract (Incremental Field or transactional CDC LSN) + transactional sink (PutSnowflakeRecord Use Transaction = true). Mismatch on either side reverts to at-least-once + idempotent target merge.

Frequently asked questions

What is Snowflake Openflow?

Snowflake Openflow is Snowflake's fully managed Apache NiFi service — it runs the entire NiFi programming model (processors, flow files, relationships, provenance, back-pressured queues) on Snowflake-managed compute called a Connect runtime. You provision one runtime per cloud + region, design flows on a visual canvas, and publish them through role-based gates. Openflow ships a first-party connector catalog (Salesforce, Workday, ServiceNow, Postgres/MySQL/SQL Server/Oracle CDC, S3/GCS, Kafka/Pulsar/Kinesis) plus a custom-processor escape hatch via signed NAR bundles. The snowflake openflow value proposition is "NiFi power without owning a NiFi cluster" — full in-flight transform and routing, but the runtime, ZooKeeper, leader election, and state storage are Snowflake's problem.

Openflow vs Fivetran vs Airbyte — when do I pick which?

The four tools cover non-overlapping sweet spots, and the openflow vs fivetran question almost always reduces to "which sweet spot does this source fall into?" Fivetran wins on plug-and-play SaaS extract — popular SaaS apps, no in-flight transform, predictable per-MAR pricing. Airbyte wins on OSS connector breadth and self-host control — when you want to write your own connector in Python via the CDK. Openflow wins on NiFi power — in-flight transformation, custom routing, CDC across many DB engines, custom Java NAR processors. Snowpipe wins on cloud-storage auto-ingest at high volume. The senior answer is rarely one tool — it's a portfolio where each tool runs in its sweet spot and Openflow takes the long tail (CDC, custom processors, complex routing).

Does Openflow support change data capture (CDC)?

Yes — Openflow ships first-party CDC connectors for Postgres (CaptureChangePostgreSQL via WAL + replication slots), MySQL (CaptureChangeMySQL via binlog), SQL Server (CaptureChangeSQLServer via CDC capture instances), and Oracle (CaptureChangeOracle via LogMiner). Each emits one flow file per row change with cdc.op (I/U/D), cdc.lsn, cdc.before, and cdc.after attributes that you can route on with RouteOnAttribute. The CDC story is where apache nifi snowflake is dramatically better than openflow vs fivetran head-to-head — Fivetran offers DB connectors too, but you cannot route insert / update / delete to different sinks in-flight without leaving the platform.

Can I write custom processors for Openflow?

Yes — the NAR (NiFi Archive) bundle is the custom-processor escape hatch. Write a Java class extending AbstractProcessor, declare its properties, implement onTrigger, and package via mvn clean package -Pnar. Sign the NAR, upload via snow openflow nar upload --file ....nar, then GRANT USAGE ON NAR BUNDLE ... TO RUNTIME .... Your custom processor appears on the canvas alongside the first-party catalog connectors. This is the durable answer for sources without a catalog connector (proprietary in-house APIs, niche SaaS apps, on-prem systems) and is one of the strongest senior-interview signals — openflow vs fivetran is not even close on this dimension because Fivetran has no escape hatch at all.

How does Openflow pricing work?

Openflow has a two-axis credit model: per-runtime credits (compute that hosts the flows, billed per hour the runtime is running) plus per-flow-file credits (the variable cost, billed per flow file processed). The per-runtime axis is controlled by SIZE (SMALL / MEDIUM / LARGE / XLARGE) and AUTO_SUSPEND (how long the runtime sleeps after idle). The per-flow-file axis is controlled by batching — MergeContent to combine many small records into fewer flow files reduces the variable cost by orders of magnitude. The right cost-optimisation moves are: set AUTO_SUSPEND = 600 on lightly-used runtimes, batch small flows with MergeContent, and move very high-volume cloud-storage drops to Snowpipe where per-COPY pricing dominates. A weekly query against OPENFLOW.USAGE should be a permanent dashboard.

What is the difference between Openflow and Snowpipe?

They target different ingest patterns. Snowpipe is an auto-ingest service for files landing in cloud storage — it watches a stage (S3/GCS/Azure Blob) via SNS/SQS notifications and runs COPY INTO micro-executions for each new file. There is no in-flight transform, no SaaS, no DB CDC. It is the cheapest path for high-volume cloud-storage drops. Openflow is the full NiFi-as-a-service platform with processors, in-flight transformation, routing, and a connector catalog spanning SaaS, DB CDC, files, and streams. The senior answer often combines them: Openflow does the source extraction and in-flight transformation, drops files into S3 with PutS3Object, and Snowpipe owns the final COPY into Snowflake at volume. Each tool runs in its sweet spot — and snowflake ingestion portfolios with both are common in 2026.

Practice on PipeCode

Lock in Openflow muscle memory

Docs explain the processors. PipeCode drills explain the decision — when NiFi power pays for the flow-canvas learning curve, when Fivetran is the right plug-and-play, when Snowpipe handles the auto-ingest path. Pipecode.ai is Leetcode for Data Engineering — pattern-first practice tuned for the production trade-offs senior data engineers actually face.

Practice ETL & pipeline problems →
Practice SQL problems →

Top comments (0)