<?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: Sai Prudhvi Neelakantam</title>
    <description>The latest articles on DEV Community by Sai Prudhvi Neelakantam (@geekindata).</description>
    <link>https://dev.to/geekindata</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%2F4239663%2F50896c3c-bf98-48ee-b955-9f1821d60acc.jpg</url>
      <title>DEV Community: Sai Prudhvi Neelakantam</title>
      <link>https://dev.to/geekindata</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/geekindata"/>
    <language>en</language>
    <item>
      <title>Databricks Genie: Can It Build My Deck and Deploy My App?</title>
      <dc:creator>Sai Prudhvi Neelakantam</dc:creator>
      <pubDate>Fri, 13 Nov 2026 10:12:47 +0000</pubDate>
      <link>https://dev.to/geekindata/databricks-genie-can-it-build-my-deck-and-deploy-my-app-2c2m</link>
      <guid>https://dev.to/geekindata/databricks-genie-can-it-build-my-deck-and-deploy-my-app-2c2m</guid>
      <description>&lt;p&gt;I used AI tools to help draft and edit this post. I checked the facts and the wording, and the original lives at &lt;a href="https://www.geekindata.com/blog/4-databricks-genie-powerpoint-webapp" rel="noopener noreferrer"&gt;geekindata.com&lt;/a&gt;. The diagrams are on that page.&lt;/p&gt;

&lt;h1&gt;
  
  
  Genie Code finishes platform-shaped jobs when context is already in the room
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Context is the product: native lakehouse and deploy awareness beats thin MCP babysitting.&lt;/li&gt;
&lt;li&gt;Optimize for artifacts people present and run (editable decks, hosted apps), not chat answers alone.&lt;/li&gt;
&lt;li&gt;Encode company PPTX templates as versioned skills; brand fidelity is not a first-prompt miracle.&lt;/li&gt;
&lt;li&gt;Capture compute shape in the deploy runbook (serverless or classic, app identity, Unity Catalog grants).&lt;/li&gt;
&lt;li&gt;Treat vendor task-success percentages as a signal; reproduce on your tables, template, and host.&lt;/li&gt;
&lt;li&gt;Human review stays on the critical path before executive or external audiences.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Can Databricks Genie make a PowerPoint from my data and respect a company template? Can it develop and deploy a web app that lands on a Genie space?&lt;/p&gt;

&lt;p&gt;Those are the questions I keep getting after demos. I have been stress-testing Genie Code on two jobs: turn governed data into an editable deck, and ship a small web app on the platform. That raises the bar for what an enterprise data platform assistant can own end to end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Named model: context → artifact → review&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context:&lt;/strong&gt; Genie Code already sees what the principal can see: tables, governance, and platform constraints. You inherit entitlements instead of pasting extracts into a consumer chatbot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Artifact:&lt;/strong&gt; The assistant continues past chat into decks, apps, and deploys. A correct SQL answer is not a board pack. A code sketch is not a hosted app.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review:&lt;/strong&gt; Editable decks still need metric-definition checks. Deployed apps still need auth, secrets, cost controls, and CI. Draft speed is the win. Unreviewed publish is the failure mode.&lt;/li&gt;
&lt;/ul&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F4-databricks-genie-powerpoint-webapp%2Fcontext-artifact-review.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F4-databricks-genie-powerpoint-webapp%2Fcontext-artifact-review.svg" alt="Three stage cards for context, artifact, and review with clear arrows between them" width="960" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1. Named model for Genie Code work. Native context feeds artifact generation. Review gates what reaches an audience or a shared host.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Context and constraint
&lt;/h2&gt;

&lt;p&gt;Most buzz around Genie Code focuses on data questions or ETL scaffolding. I wanted the day-to-day path: can it produce artifacts people actually present and run? After those tests, it feels closer to Claude Code or Cursor than to shallow autocomplete, with enterprise data security already in the room. Native Databricks context on tables, governance, and platform constraints means less token waste restating warehouse topology.&lt;/p&gt;

&lt;p&gt;Genie Code matters when it continues past chat into artifacts. If it reasons about deploy constraints, you spend less time as the human MCP adapter. Figure 2 is the ownership split I use when someone asks whether a generic coding agent with thin MCP is "the same thing."&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F4-databricks-genie-powerpoint-webapp%2Fnative-vs-generic.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F4-databricks-genie-powerpoint-webapp%2Fnative-vs-generic.svg" alt="Native Genie Code path versus generic coding agent plus thin MCP" width="960" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2. Same class of coding help, different babysitting load. Native context finishes platform-shaped jobs. Generic agents stay flexible across stacks but re-teach the warehouse and deploy reality every session.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Deck generation as a skill-backed workflow
&lt;/h3&gt;

&lt;p&gt;I connected Genie Code with an open-source PPTX skill (the same family used with Claude Code) to build a PowerPoint from Databricks data. Instead of chat-only insights, it generated a full editable multi-slide deck with charts. That is the difference between a screenshot of an answer and a boardroom-ready artifact for monthly or quarterly reviews. Figure 3 is the path: governed metrics into a skill, then an editable deck, then an editorial pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Templates as deliberate customization, not magic
&lt;/h3&gt;

&lt;p&gt;If you customize the skill, it can work from a company template: unpack the structure, then pick and replace slides for the related data. Exact brand fidelity is a skill and asset problem, not a vibe. Budget time to encode the template rules. Do not expect a first prompt to invent your corporate master.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. App build and deploy with platform-native constraints
&lt;/h3&gt;

&lt;p&gt;App development and deploy inside Databricks is possible from IDEs like Cursor or Claude Code with Databricks MCP, but I still have to point those agents at the right path. Genie Code already has platform context. In my run a one-line prompt was enough for it to create an empty app, plan the work, and open the app page while compute started. After one nudge to continue, it wrote app.py, app.yaml and requirements.txt, deployed through the workspace and apps APIs, and the app reached Running on a Databricks Apps host.&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F4-databricks-genie-powerpoint-webapp%2Fskill-deck-deploy-path.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F4-databricks-genie-powerpoint-webapp%2Fskill-deck-deploy-path.svg" alt="Skill-backed deck path and platform deploy path with review gates" width="960" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3. Two artifact paths. Top: governed metrics through a PPTX skill into an editable deck, then editorial review. Bottom: app bound to a Genie space, compute-shape check, host deploy, then CI and identity before broad reach.&lt;/em&gt;&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%2Ffxqg3fne8qbve71kcqeu.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%2Ffxqg3fne8qbve71kcqeu.png" alt="Databricks Apps details page for a demo app: status Running, Medium compute, source path under the workspace user folder, and six successful deployment steps, with the app URL and IDs masked" width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 4. A demo app on its details page right after deploy. The compute shape (Medium) and the deployment record (source path, then every step from stop to start) sit on one page, so that is where I copy them from into the deploy runbook.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Running is not the same as working. Genie Code gave the app's service principal SELECT on the table, then stopped and asked before granting USE CATALOG and USE SCHEMA. Until someone approves those, the chart shows "Failed to load data" (Figure 5). That is the default I want from an agent, and it means the grants belong in the runbook, not in a follow-up prompt.&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%2Ft0dtix3x74a1ik6ji6px.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%2Ft0dtix3x74a1ik6ji6px.png" alt="Genie Code summary for a demo app: source files written, app deployed, SELECT granted on the table, and USE CATALOG and USE SCHEMA still waiting for approval, with the workspace part of the app URL blurred" width="395" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 5. The agent's own summary after deploy. Table access is granted, but the catalog and schema grants wait for my OK, so the app runs and the chart cannot load data yet.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The app does not run as me. It gets its own service principal, and signed-in users go through a separate OAuth client with their own scopes (Figure 6). Decide which identity reads the data before you share the link.&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%2F9nc5kpg8xwrbf5mgh03n.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%2F9nc5kpg8xwrbf5mgh03n.png" alt="Databricks Apps Authorization page for a demo app: app authorization through its own service principal with client ID and secret as environment variables, and user authorization through a separate OAuth client with two default scopes, with the IDs blurred" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 6. Two identities on one app. The service principal acts for the app; the OAuth client acts for the signed-in user. Pick one on purpose.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The deck run hit the compute-shape wall instead. Serverless compute was not enabled in that workspace, so Genie Code put the python-pptx code in a notebook and ran it once on the existing cluster (Figure 7). Capture both facts, the grants and the compute you actually have, in the runbook so the next person does not rediscover them under demo pressure.&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%2F21mlwd9qake83cu0n4d1.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%2F21mlwd9qake83cu0n4d1.png" alt="Genie Code deck prompt followed by its explanation: serverless compute is not enabled, so it created a notebook and started a one-time run on the existing demo cluster, with the run ID blurred" width="395" height="974"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 7. The deck build falls back to a notebook on a classic cluster because serverless is off. The agent explains the pivot instead of failing silently.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The chart in that deck is native, not a picture. In a rerun against a three-segment demo table, the pptx Genie Code built carries the chart as chart XML with an embedded workbook, so the values sit behind the chart and can be edited in place (Figure 8).&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%2F04erglmbpednk7fgtcg9.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%2F04erglmbpednk7fgtcg9.png" alt="A bar chart of total value by segment in the generated deck, opened in LibreOffice Impress, with the chart's Data Table dialog showing categories A, B and C with values 42, 28 and 55" width="732" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 8. The generated deck opened in LibreOffice Impress, cropped below the slide title. The chart's Data Table shows the embedded values (A 42, B 28, C 55), which is what makes it editable rather than a screenshot.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Benchmarks as a signal, not a religion
&lt;/h3&gt;

&lt;p&gt;Databricks has reported Genie Code at about 77.1% success on real-world tasks versus about 32.1% for leading coding agents using MCP. Treat that as evidence that native context changes outcomes, not as a guarantee for your Monday ticket. Reproduce the tasks that matter: deck from governed metrics, app bound to a Genie space, deploy on the compute you actually use.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Human review stays on the critical path
&lt;/h3&gt;

&lt;p&gt;Editable decks still need a human to check claims against metric definitions. Deployed apps still need auth, secrets, and cost controls. Genie Code shortens the path to a draft. It does not retire ownership.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Chat answers mistaken for board artifacts.&lt;/strong&gt;&lt;br&gt;
A correct SQL answer is not a deck. Design the skill path and template rules explicitly. Figure 3 is the minimum shape.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Template hope without template work.&lt;/strong&gt;&lt;br&gt;
One brand prompt yields a generic theme. Exact masters need encoding and test renders.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generic agent plus thin MCP mistaken for native context.&lt;/strong&gt;&lt;br&gt;
You get code, then babysit deploy topology and CLI availability. Figure 2 is that babysitting made visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serverless assumed to be there.&lt;/strong&gt;&lt;br&gt;
In my workspace it was off, so the deck build fell back to a notebook on a classic cluster. Identity wiring and egress differ too. Capture compute shape in the deploy runbook.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benchmark theater.&lt;/strong&gt;&lt;br&gt;
You cite 77.1% and skip smoke tests on your tables, template, and app host.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unreviewed publish.&lt;/strong&gt;&lt;br&gt;
An agent can deploy. Gate promotion, app identity, and catalog grants before broad reach. Figure 1 puts review on the critical path on purpose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use as-is or adapt
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use as-is&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Genie Code allowed for draft decks and prototype apps; production publish follows existing review and CI gates.&lt;/li&gt;
&lt;li&gt;Company PPTX templates encoded as versioned skills or assets with a smoke render checklist.&lt;/li&gt;
&lt;li&gt;Auto-generated charts must resolve to governed tables or semantic metrics, not pasted CSV extracts.&lt;/li&gt;
&lt;li&gt;Deploy runbooks document compute shape, app identity, and the Unity Catalog grants the app's service principal needs; serverless availability is checked, not assumed.&lt;/li&gt;
&lt;li&gt;Human review mandatory before external or executive audiences see generated decks.&lt;/li&gt;
&lt;li&gt;Compare native assistant vs MCP-from-IDE on a fixed internal task set periodically; do not rely only on vendor percentages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Adapt before you use&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Native assistants reduce context assembly on platform-shaped work. You accept vendor coupling. External coding agents stay flexible across stacks but re-teach warehouse and deploy reality every session.&lt;/p&gt;

&lt;p&gt;Skill-based decks are powerful and still fragile around complex masters and semantic charts. Plan an editorial pass. Removing the last human check is how wrong KPIs reach the all-hands pack.&lt;/p&gt;

&lt;p&gt;Assistant deploy speeds prototypes. Production still wants CI, reviews, and environment separation. Clear the first fog; do not bypass the release train.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;Both demos are in my public tech-demos repo: a &lt;a href="https://github.com/geekindata/tech-demos/tree/main/demos/databricks-apps-hello" rel="noopener noreferrer"&gt;minimal Databricks App you deploy with the CLI&lt;/a&gt; and a &lt;a href="https://github.com/geekindata/tech-demos/tree/main/demos/deck-generation-native-chart" rel="noopener noreferrer"&gt;script that builds a deck with native, editable charts&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;p&gt;This also leaves a question for Copilot in Microsoft Fabric: agent mode with context of Fabric items and data soon? Track that peer question when you compare platform assistants, not only Databricks Genie.&lt;/p&gt;

&lt;p&gt;Primary references: &lt;a href="https://www.databricks.com/product/business-intelligence/genie" rel="noopener noreferrer"&gt;Genie Code&lt;/a&gt;, Anthropic agent skills docs, Databricks docs for Genie and Databricks Apps, and Databricks materials on Genie Code task success with vs without native platform context.&lt;/p&gt;

&lt;p&gt;Context. Artifact. Review. Three steps. Native beats naive when the job is platform-shaped.&lt;/p&gt;

</description>
      <category>databricks</category>
      <category>ai</category>
      <category>enterprisedata</category>
      <category>automation</category>
    </item>
    <item>
      <title>Azure Custom Vision: How Do You Train and Run Image Classification in an Azure Function?</title>
      <dc:creator>Sai Prudhvi Neelakantam</dc:creator>
      <pubDate>Fri, 13 Nov 2026 10:12:11 +0000</pubDate>
      <link>https://dev.to/geekindata/azure-custom-vision-how-do-you-train-and-run-image-classification-in-an-azure-function-8md</link>
      <guid>https://dev.to/geekindata/azure-custom-vision-how-do-you-train-and-run-image-classification-in-an-azure-function-8md</guid>
      <description>&lt;p&gt;I used AI tools to help draft and edit this post. I checked the facts and the wording, and the original lives at &lt;a href="https://www.geekindata.com/blog/3-azure-image-classification" rel="noopener noreferrer"&gt;geekindata.com&lt;/a&gt;. The diagrams are on that page.&lt;/p&gt;

&lt;h1&gt;
  
  
  Keep the UI boring; make prediction operable
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep the UI boring: upload, predict, show label and confidence.&lt;/li&gt;
&lt;li&gt;Validate type, size, and decodability on the server before inference.&lt;/li&gt;
&lt;li&gt;Prediction credentials stay on the backend; the browser talks only to the app API.&lt;/li&gt;
&lt;li&gt;Treat low confidence as a first-class UI outcome, not a silent top-label win.&lt;/li&gt;
&lt;li&gt;Log correlation id, iteration id, latency, and top-N labels on every call.&lt;/li&gt;
&lt;li&gt;Publish Custom Vision iterations like app releases: smoke set plus rollback.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Custom Vision can get you from labeled images to a prediction endpoint quickly. The product work starts after the happy path: bad uploads, low-confidence answers, iteration that breaks the published endpoint, and no breadcrumbs when the label is wrong.&lt;/p&gt;

&lt;p&gt;Keep the UI boring: upload, predict, show label and confidence. Put the complexity in data quality, validation, request limits, logging, and a controlled publish path for new iterations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Named model: upload → predict → explain → iterate&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Upload:&lt;/strong&gt; server-side type, size, and decode checks before you spend an inference call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predict:&lt;/strong&gt; app API owns timeouts, retries, and credentials (keys or managed identity).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explain:&lt;/strong&gt; UI always shows label plus confidence; low score is a first-class outcome.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Iterate:&lt;/strong&gt; train, smoke a fixed image set, publish the iteration, keep a rollback path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contract:&lt;/strong&gt; Custom Vision owns the score; the web app owns hygiene, keys, and breadcrumbs.&lt;/li&gt;
&lt;/ul&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F3-azure-image-classification%2Fupload-predict-explain.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F3-azure-image-classification%2Fupload-predict-explain.svg" alt="Four stages: upload with validation, predict behind the app API, explain label and confidence, iterate as a controlled release" width="960" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1. Upload, predict, explain, iterate. The UI stays simple on purpose. Operability lives in validation, the API boundary, honest confidence, and a publish path you can roll back.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Context and constraint
&lt;/h2&gt;

&lt;p&gt;I have seen too many vision demos that look polished until the first bad upload, the first low-confidence answer, or the first model iteration that breaks the published endpoint. A good demo becomes a product when input validation, request limits, logging, and a path to retrain stay in place from day one.&lt;/p&gt;

&lt;p&gt;Custom Vision (or the equivalent Azure image classification path you choose under Microsoft Foundry / Azure AI Services) should own prediction. The web app should own upload hygiene, auth if you need it, presentation of labels and confidence, and the operational breadcrumbs that let you debug wrong answers later. If the UI tries to be clever, people stop trusting the score. If the backend skips basics, you cannot operate the cleverness you shipped.&lt;/p&gt;

&lt;p&gt;Figure 2 is the Learn surface that makes the user contract visible: labels and confidence, not a second story invented in the app shell.&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%2F39dl4lpzy3p7u5ndmk2u.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%2F39dl4lpzy3p7u5ndmk2u.png" alt="Custom Vision example of labeled image classes" width="799" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2. Labels and confidence are the user contract. The training UI is where iteration happens; the web app should not invent a second story. Source: &lt;a href="https://learn.microsoft.com/en-us/azure/ai-services/custom-vision-service/overview" rel="noopener noreferrer"&gt;Microsoft Learn: Custom Vision overview&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Figure 3 is the project home where iterations live. Treat a published endpoint as a release artifact, not as a casual overwrite after lunch.&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%2Foq9j5lgjg2uyoho9tys4.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%2Foq9j5lgjg2uyoho9tys4.png" alt="Custom Vision project home in the browser" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3. Iteration lives in the project surface. Treat published endpoints as release artifacts, not as a casual overwrite. Source: &lt;a href="https://learn.microsoft.com/en-us/azure/ai-services/custom-vision-service/overview" rel="noopener noreferrer"&gt;Microsoft Learn: Custom Vision overview&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Start with the user flow, not the model card
&lt;/h3&gt;

&lt;p&gt;The journey should be obvious: choose an image, submit, see a result. Minimal layout keeps focus on the core interaction. Extra toggles, advanced panels, and decorative charts can wait until the happy path is boringly reliable. If the flow is complicated, the AI feature feels harder than it is. Figure 1 is that boring path drawn as four jobs.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Validate before you spend an inference call
&lt;/h3&gt;

&lt;p&gt;Check file type, size, and basic image decodability on the server. Reject clearly. Do not stream arbitrary blobs to the prediction endpoint and hope. Validation protects cost, protects the service from garbage, and gives users a faster failure than a timeout wrapped as something went wrong.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Wrap prediction in boring, predictable backend behavior
&lt;/h3&gt;

&lt;p&gt;Timeouts, retries for transient faults, and mapped error responses belong in the API layer. Return plain-language failures when inference fails. Show label and confidence in plain language when it succeeds. Low confidence is a first-class outcome: say so in the UI instead of pretending the top label is gospel.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Keep secrets and keys out of the browser
&lt;/h3&gt;

&lt;p&gt;Prediction keys and training keys belong on the server or in managed identity patterns, not in frontend bundles. A static page that calls Custom Vision directly is a short path to key leakage and uncontrolled quota burn. The browser uploads to your app; your app calls Azure. Figure 4 is the ownership split that keeps the key out of view-source.&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F3-azure-image-classification%2Fkeys-behind-api.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F3-azure-image-classification%2Fkeys-behind-api.svg" alt="Browser uploads to the app API; the API holds keys or managed identity and calls Custom Vision; a red anti-pattern warns against keys in the browser bundle" width="960" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 4. Browser talks to your app. Your app talks to Custom Vision. Keys and managed identity stay on the server. A browser-side key is how quota burn gets a silent owner.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Log enough to debug bad results
&lt;/h3&gt;

&lt;p&gt;Store correlation ids, model name or iteration id, latency, top labels, and whether the user accepted or corrected the result if you collect that. You do not need the raw image forever in every environment, but you need a path to reproduce class of failures. Without iteration ids in logs, root cause becomes folklore after the next publish.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Treat Custom Vision iteration as a release
&lt;/h3&gt;

&lt;p&gt;New tags, new training images, and a newly published iteration change product behavior. Promote iterations the way you promote app builds: note what changed, smoke-test a fixed image set, and keep a rollback to the previous published iteration. Narrow classifiers drift when the world changes. Plan for that drift instead of discovering it in a stakeholder meeting. Figure 5 is the release shape.&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F3-azure-image-classification%2Fiteration-as-release.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F3-azure-image-classification%2Fiteration-as-release.svg" alt="Train, smoke a fixed image set, publish the iteration to live, with a dashed rollback to the previous published iteration" width="960" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 5. Train, smoke, publish, live. The dashed return is rollback to the previous published iteration. Log the iteration id on every prediction so a bad publish is diagnosable.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Demo happy path only.&lt;/strong&gt;&lt;br&gt;
PNG of a clear object on a white background. Real users upload HEIC phone photos, screenshots, and five-megabyte scans. The app chokes or the model shrugs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Confidence ignored.&lt;/strong&gt;&lt;br&gt;
Always show the top label in bold. Users trust 0.41 the same as 0.97. That is how wrong operational decisions get a nice UI.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keys in the browser.&lt;/strong&gt;&lt;br&gt;
Someone views source, copies the prediction key, and your bill explains itself next month. Figure 4 is the failure made visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No iteration discipline.&lt;/strong&gt;&lt;br&gt;
Retrain in the portal, publish, and hope. Yesterday's smoke images now misclassify and nobody can say which publish did it. Figure 5 is the discipline that prevents that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Logging without model identity.&lt;/strong&gt;&lt;br&gt;
You know the request failed or looked weird. You do not know which iteration served it. Support becomes archaeology.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unbounded uploads.&lt;/strong&gt;&lt;br&gt;
No size limit, no rate limit, no auth on an internal tool that somehow became external. Inference cost and abuse arrive together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use as-is or adapt
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use as-is&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Server-side validation for type, size, and decodability before prediction.&lt;/li&gt;
&lt;li&gt;Prediction credentials only on the backend; browser talks to the app API.&lt;/li&gt;
&lt;li&gt;UI always shows label plus confidence; low-confidence threshold is product-defined.&lt;/li&gt;
&lt;li&gt;Logs include correlation id, iteration or model id, latency, and top-N labels.&lt;/li&gt;
&lt;li&gt;Published iterations are treated as releases with a smoke set and rollback.&lt;/li&gt;
&lt;li&gt;Rate limits and auth posture documented for internal versus public exposure.&lt;/li&gt;
&lt;li&gt;Retraining ownership and data retention rules written before the first production upload.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Adapt before you use&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Custom Vision is fast to stand up for a narrow task. It is not a substitute for a carefully engineered vision stack when you need detection, segmentation, or strict latency at the edge. Choose it when labeled examples and a classification answer are enough for the product decision.&lt;/p&gt;

&lt;p&gt;A thin web app is easy to explain and easy to replace. A thicker product shell (auth, history, human review queue) takes longer but is what internal tools often need after week two. Do not pretend the upload page is the whole system if reviewers must correct labels for retraining.&lt;/p&gt;

&lt;p&gt;Hosting the model via Azure versus exporting for edge runtimes changes your update story and your offline story. Pick based on where images are allowed to travel, not based on which quickstart you pasted first.&lt;/p&gt;

&lt;p&gt;Primary references: Microsoft Learn on &lt;a href="https://learn.microsoft.com/en-us/azure/ai-services/custom-vision-service/" rel="noopener noreferrer"&gt;Custom Vision&lt;/a&gt;, &lt;a href="https://learn.microsoft.com/en-us/azure/ai-services/custom-vision-service/overview" rel="noopener noreferrer"&gt;image classification&lt;/a&gt;, and Azure AI / AI Services authentication patterns for keeping keys off the browser. Prefer current Microsoft Foundry naming when your deploy target has moved under that umbrella.&lt;/p&gt;

&lt;p&gt;Upload. Predict. Explain. Iterate. Four jobs. One score the user can actually trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.geekindata.com/blog/2-pose-estimation" rel="noopener noreferrer"&gt;Pose Estimation: MediaPipe or YOLOPose for Real-Time Pose Classification?&lt;/a&gt; (a real-time vision loop with its own latency budget)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>customvision</category>
      <category>imageclassification</category>
      <category>webapp</category>
    </item>
    <item>
      <title>Pose Estimation: MediaPipe or YOLOPose for Real-Time Pose Classification?</title>
      <dc:creator>Sai Prudhvi Neelakantam</dc:creator>
      <pubDate>Fri, 13 Nov 2026 10:04:10 +0000</pubDate>
      <link>https://dev.to/geekindata/pose-estimation-mediapipe-or-yolopose-for-real-time-pose-classification-392m</link>
      <guid>https://dev.to/geekindata/pose-estimation-mediapipe-or-yolopose-for-real-time-pose-classification-392m</guid>
      <description>&lt;p&gt;I used AI tools to help draft and edit this post. I checked the facts and the wording, and the original lives at &lt;a href="https://www.geekindata.com/blog/2-pose-estimation" rel="noopener noreferrer"&gt;geekindata.com&lt;/a&gt;. The diagrams are on that page.&lt;/p&gt;

&lt;h1&gt;
  
  
  Pose estimation is a systems problem, not a model bake-off
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Treat pose as a continuous capture → infer → render loop under one latency budget.&lt;/li&gt;
&lt;li&gt;Measure p50 and p95 end-to-end on the demo machine, not only model milliseconds.&lt;/li&gt;
&lt;li&gt;Separate inference work from overlays so drawing cannot stall the next frame.&lt;/li&gt;
&lt;li&gt;Name a frame-drop policy under load (prefer drop oldest for live UX).&lt;/li&gt;
&lt;li&gt;Pick MediaPipe-style vs YOLOPose-style for systems shape, not a bake-off slide.&lt;/li&gt;
&lt;li&gt;Write capture conditions (light, distance, people count) into the product spec.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Point a camera at a person, draw a skeleton, call it live. The clip demo survives. The live stream often does not: lighting swings, frames drop, backgrounds get busy, and people feel 80 ms of lag even when they cannot name the number.&lt;/p&gt;

&lt;p&gt;Keypoint accuracy without a calm loop is a lab number. What users experience is time from frame grab to a stable overlay. Capture, inference, and render are three jobs. Each can fail while the other two look fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Named model: capture → infer → render&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Capture:&lt;/strong&gt; camera or stream with a timestamp at frame grab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preprocess / infer:&lt;/strong&gt; resize once, run keypoints on their own worker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Render:&lt;/strong&gt; overlays and confidence rules that never block the next grab.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contract:&lt;/strong&gt; one shared latency budget (capture timestamp to overlay), plus an explicit backpressure and drop policy when the queue fills.&lt;/li&gt;
&lt;/ul&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F2-pose-estimation%2Fcapture-infer-render-loop.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F2-pose-estimation%2Fcapture-infer-render-loop.svg" alt="Capture, preprocess, infer, and render stages in a continuous loop under one shared latency budget" width="960" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1. Capture, preprocess, infer, render. Solid arrows move the frame forward. The return path is the next frame. The band under the stages is the latency budget users actually feel.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Context and constraint
&lt;/h2&gt;

&lt;p&gt;I treat pose demos as product exercises. Frames have to enter the pipeline. Inference has to finish on time. Results have to present without lying about confidence. If any of those jobs lags, the experience feels unreliable even when the offline keypoint table looks strong.&lt;/p&gt;

&lt;p&gt;You are not only detecting joints. You are shipping a stream processor that must stay responsive when conditions change. Optimize the loop. Model milliseconds on a warm GPU stay a lab number until you measure them on the same camera and hardware the app will use.&lt;/p&gt;

&lt;p&gt;MediaPipe-style landmark runtimes and YOLOPose-style detect-then-pose stacks answer different ownership questions. Figure 2 is the shape difference, not a leaderboard. Lean local landmarks keep fewer stages in the loop. Detect-then-pose buys multi-person association and costs more stages to budget and observe. Pick the shape that matches your latency and ownership budget before you argue mAP.&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F2-pose-estimation%2Fruntime-shape-tradeoff.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F2-pose-estimation%2Fruntime-shape-tradeoff.svg" alt="Lean MediaPipe-style landmark path versus YOLOPose-style detect-then-pose path as systems shapes" width="960" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2. Systems tradeoff, not a bake-off. Left is a lean landmark path. Right adds person detect before pose. More stages means more places for queues and association errors to hide.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The same discipline shows up in other vision products. Figure 3 is an Azure AI Vision image-analysis surface from Microsoft Learn. Boxes and tags are a different output. The lesson still transfers: keep the frame path explicit. Pose work swaps boxes for landmarks and still fails when presentation flickers or the path is opaque.&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%2Fopc9gumv7s5hn0w9vi6s.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%2Fopc9gumv7s5hn0w9vi6s.png" alt="Object detection overlay example from Azure AI Vision image analysis" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3. Vision pipelines succeed when the frame path stays explicit: capture, analyze, present. Pose work has the same loop, just with landmarks instead of boxes. Source: &lt;a href="https://learn.microsoft.com/en-us/azure/ai-services/computer-vision/overview-image-analysis" rel="noopener noreferrer"&gt;Microsoft Learn: image analysis overview&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Budget the frame path first
&lt;/h3&gt;

&lt;p&gt;Set target resolution, target FPS, and maximum end-to-end latency before you reach for a heavier backbone. Resize only as much as the model needs. Skip redundant color conversions and double copies between CPU and GPU. If capture already gives a usable size, do not upscale for aesthetics and then downscale for inference. Figure 1 is the budget surface: every stage eats from the same band from t0 grab to t3 overlay.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Separate inference from visualization
&lt;/h3&gt;

&lt;p&gt;Keep the inference worker off the render path. Skeleton drawing, trail smoothing, and fancy overlays must not block the next frame grab. When visualization shares a thread with inference, a pretty effect becomes a latency bug. Clear overlays beat decorative ones when confidence flickers.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Measure end-to-end, in the real environment
&lt;/h3&gt;

&lt;p&gt;Instrument capture timestamp, preprocessed frame ready, inference done, and frame presented. Track p50 and p95, not only averages. Measure on the laptop or edge hardware you will demo on, with the same camera and similar ambient load. A desktop GPU number does not forgive a thermal-throttled demo machine.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Name backpressure before the queue grows
&lt;/h3&gt;

&lt;p&gt;Live systems need an explicit rule for what you discard under load. Figure 4 contrasts the live choice (drop oldest, keep presenting fresh frames) with the accidental failure (drop newest, let the queue go stale while capture still looks busy). Bound queue depth. Log drops. Do not invent the policy in a hallway demo.&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F2-pose-estimation%2Fbackpressure-drop-policy.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F2-pose-estimation%2Fbackpressure-drop-policy.svg" alt="Short queue between capture and infer with drop-oldest versus drop-newest policies" width="960" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 4. Backpressure needs a named drop policy. Prefer drop oldest for live UX. Dropping newest is how overlays lag while the camera path still looks busy.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Design for unstable confidence
&lt;/h3&gt;

&lt;p&gt;Pose models wobble on occlusions, odd angles, and fast motion. Decide how the UI behaves when confidence drops: hold the last good pose briefly, fade the skeleton, or mark low-confidence joints. Silent jitter reads as broken AI. Explicit uncertainty reads as an honest system.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Keep the pipeline lean enough to reason about
&lt;/h3&gt;

&lt;p&gt;Fewer stages mean fewer places for backlog to hide. Prefer a boring path: capture, light preprocess, infer, overlay, display. Add tracking, multi-person association, or recording only when you can name the product need. Each extra stage needs its own backpressure story, or you will drop frames in the wrong place and not know why. That is why Figure 2 matters before you add a second detector "for free."&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Treat demo conditions as requirements
&lt;/h3&gt;

&lt;p&gt;Lighting, distance to camera, clothing contrast, and number of people in frame belong in the spec. Write them down. A pipeline tuned on a clean studio take fails in a conference hallway. If the product must work in hallways, collect failure clips there and tune against those clips, not marketing stills.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Model-only optimization.&lt;/strong&gt;&lt;br&gt;
You shave 3 ms off inference and ignore 40 ms of preprocess and copy overhead. The user feels nothing. The slide looks better.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ideal-case demos.&lt;/strong&gt;&lt;br&gt;
Perfect light, one person, facing the camera, no occlusion. Stakeholders applaud. The first real user stands side-on under fluorescent lights and the skeleton falls apart.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shared thread for infer and draw.&lt;/strong&gt;&lt;br&gt;
Overlay code stalls capture. Apparent FPS collapses. You blame the model.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No backpressure policy.&lt;/strong&gt;&lt;br&gt;
Queues grow, latency climbs, then you drop newest instead of oldest (or the reverse) without a deliberate choice. Figure 4 is that failure made visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UI that hides uncertainty.&lt;/strong&gt;&lt;br&gt;
Low-confidence joints still draw at full opacity. People trust wrong elbows. Later that trust debt shows up as "computer vision does not work here."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Environment mismatch.&lt;/strong&gt;&lt;br&gt;
Train and eval on clean datasets. Ship on webcams where auto-exposure fights the face. Domain shift is the default, not a surprise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bake-off without a product shape.&lt;/strong&gt;&lt;br&gt;
You compare MediaPipe and YOLOPose on a static accuracy table and never decide lean single-person versus detect-then-pose multi-person. The slide winner loses on the hardware you actually demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use as-is or adapt
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use as-is&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;End-to-end latency budget (capture to overlay) with a p95 target on target hardware.&lt;/li&gt;
&lt;li&gt;Explicit pipeline stages and ownership: capture, preprocess, infer, render.&lt;/li&gt;
&lt;li&gt;Backpressure and frame-drop policy under load (name drop oldest vs drop newest).&lt;/li&gt;
&lt;li&gt;Confidence visualization rules for low-quality joints and lost tracks.&lt;/li&gt;
&lt;li&gt;Supported capture conditions (lighting, distance, people count) as product requirements.&lt;/li&gt;
&lt;li&gt;A demo checklist that matches those conditions, not a studio-only path.&lt;/li&gt;
&lt;li&gt;Separation of inference work from UI effects so overlays cannot stall the loop.&lt;/li&gt;
&lt;li&gt;Runtime choice framed as systems shape (lean landmarks vs detect-then-pose), not a leaderboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Adapt before you use&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lower resolution and simpler models buy latency and stability. You give up fine-grained joint precision. For coaching, ergonomics, or interactive demos, stability usually wins. For offline analysis where you can wait, accuracy can win. Name the product before you argue mAP.&lt;/p&gt;

&lt;p&gt;Local inference reduces round trips and privacy surface. Cloud inference can give heavier models and easier updates. Real-time UX rarely forgives a flaky network hop. If you must go to the cloud, budget for jitter and design a degraded local mode, or accept that real-time becomes near-real-time with retries.&lt;/p&gt;

&lt;p&gt;Multi-person tracking multiplies association errors and CPU cost. Ship single-person well before you promise a crowd. A crisp single skeleton beats three flickering ones in every stakeholder review I have run.&lt;/p&gt;

&lt;p&gt;Primary references: docs for the pose runtime you actually ship (for example &lt;a href="https://ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker" rel="noopener noreferrer"&gt;MediaPipe Pose&lt;/a&gt; or an equivalent keypoint stack), OpenCV capture and timing guidance, and the model card for keypoint definitions and known failure cases. Prefer vendor docs for your deploy target, not a blog benchmark from a different GPU. For the Learn surface in Figure 3, see &lt;a href="https://learn.microsoft.com/en-us/azure/ai-services/computer-vision/overview-image-analysis" rel="noopener noreferrer"&gt;Microsoft Learn: image analysis overview&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Capture. Infer. Render. Three stages. One latency budget. Honesty when confidence drops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.geekindata.com/blog/3-azure-image-classification" rel="noopener noreferrer"&gt;Azure Custom Vision: How Do You Train and Run Image Classification in an Azure Function?&lt;/a&gt; (the same honesty about low confidence, behind an Azure Function)&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>computervision</category>
      <category>poseestimation</category>
      <category>realtimeai</category>
      <category>inference</category>
    </item>
    <item>
      <title>Fabric Airflow: Is It Possible to Use Apache Airflow with Fabric?</title>
      <dc:creator>Sai Prudhvi Neelakantam</dc:creator>
      <pubDate>Fri, 13 Nov 2026 10:03:35 +0000</pubDate>
      <link>https://dev.to/geekindata/fabric-airflow-is-it-possible-to-use-apache-airflow-with-fabric-319n</link>
      <guid>https://dev.to/geekindata/fabric-airflow-is-it-possible-to-use-apache-airflow-with-fabric-319n</guid>
      <description>&lt;p&gt;I used AI tools to help draft and edit this post. I checked the facts and the wording, and the original lives at &lt;a href="https://www.geekindata.com/blog/1-fabric-airflow" rel="noopener noreferrer"&gt;geekindata.com&lt;/a&gt;. The diagrams are on that page.&lt;/p&gt;

&lt;h1&gt;
  
  
  Keep Fabric executing; put Airflow on schedule and graph
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fabric executes the work; Airflow owns schedule, graph, retries, and alerts.&lt;/li&gt;
&lt;li&gt;Success means Fabric &lt;strong&gt;terminal state&lt;/strong&gt;, not trigger acceptance.&lt;/li&gt;
&lt;li&gt;Prefer many thin tasks named for the pipeline step.&lt;/li&gt;
&lt;li&gt;Put quality gates in the DAG where they are visible.&lt;/li&gt;
&lt;li&gt;Do not rebuild Fabric transforms inside Airflow operators.&lt;/li&gt;
&lt;li&gt;Reach for Airflow when cross-job dependencies need an honest graph.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yes, when you treat them as two planes. Fabric should do the work. Airflow should own the schedule, the dependency graph, retries, and the on-call story of the run.&lt;/p&gt;

&lt;p&gt;Airflow earns its place when a Fabric environment looks fine in the portal and still falls apart because three jobs have to finish before a fourth can start. Native schedules handled single jobs. They did not explain a graph. Collapsing coordination into notebooks made every change feel riskier than the transform itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Named model: two planes&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Execution plane (Fabric):&lt;/strong&gt; notebooks, pipelines, lakehouse work, warehouse ops, semantic refresh.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration plane (Airflow):&lt;/strong&gt; schedule, dependencies, retries, alerts, run history humans can read.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contract:&lt;/strong&gt; each Airflow task waits for Fabric &lt;strong&gt;terminal state&lt;/strong&gt;, not trigger acceptance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shape:&lt;/strong&gt; many thin tasks named for the pipeline step; quality gates are visible DAG steps.&lt;/li&gt;
&lt;/ul&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F1-fabric-airflow%2Ftwo-planes.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F1-fabric-airflow%2Ftwo-planes.svg" alt="Two planes: Airflow DAG on the left coordinates land, validate, transform, and publish; Fabric on the right runs notebooks, lakehouse work, and semantic refresh; the link is wait for terminal state" width="960" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1. Airflow coordinates, Fabric executes. The solid arrow is wait for terminal state. The dashed return is status, run id, and alert text. Not fire and forget.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Context and constraint
&lt;/h2&gt;

&lt;p&gt;Fabric notebooks and pipelines are strong at doing work. They are weaker as the calendar and dependency graph for everything around them. The moment the path is land, validate, transform, publish, you need an orchestration plane that is not pretending to be another transform engine.&lt;/p&gt;

&lt;p&gt;Airflow fits when you want an honest DAG. Keep tasks thin. Call Fabric. Do not rebuild Fabric inside operators because it was convenient on a Friday. If you start reimplementing transforms in Airflow Python, you have created a second source of truth. Convenience is how orchestration layers go thick and then opaque.&lt;/p&gt;

&lt;p&gt;Fabric Airflow jobs make that split concrete in the product surface. Figure 2 is the Learn tile that starts a DAG whose job is to run a Fabric item, not to host the Spark logic. The orchestrator stays thin on purpose.&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%2Frbk2jc1elpkf2fcjpgkl.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%2Frbk2jc1elpkf2fcjpgkl.png" alt="Apache Airflow job canvas tile for running a Fabric item" width="800" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2. Start from Run Fabric Artifact when the DAG should trigger notebooks or pipelines without stuffing transform logic into the orchestrator. Source: &lt;a href="https://learn.microsoft.com/en-us/fabric/data-factory/apache-airflow-jobs-run-fabric-item-job" rel="noopener noreferrer"&gt;Microsoft Learn: run a Fabric item using Apache Airflow&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. One DAG, thin tasks, honest names
&lt;/h3&gt;

&lt;p&gt;Map the flow so a new hire can read it without a walkthrough: land, validate, transform, publish, notify. Each task should do one clear thing. If a task grows into everything after bronze, you lose clean retries and you lose the ability to say which step actually failed. Prefer many small operators that call Fabric over one giant operator that hides a private workflow. Figure 3 shows the shape difference.&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F1-fabric-airflow%2Fthin-vs-fat-tasks.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F1-fabric-airflow%2Fthin-vs-fat-tasks.svg" alt="Thin named DAG tasks versus one fat medallion operator" width="960" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3. Thin tasks keep retries and blame local. One fat bronze-to-gold operator turns a gold failure into a full rerun.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Fabric executes; Airflow coordinates
&lt;/h3&gt;

&lt;p&gt;Trigger Fabric jobs, pipelines, or notebooks from Airflow. Do not copy the Spark logic into Airflow Python for speed. The execution plane stays in Fabric where capacity, identities, and lakehouse bindings already live. Airflow should pass parameters, wait for completion, and react to status. When status is ambiguous, fix the Fabric job contract. Do not paper over it with longer sleeps. Figure 1 is the ownership split; Figure 2 is the product entry point that keeps transforms out of the DAG.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Explicit success and failure contracts
&lt;/h3&gt;

&lt;p&gt;Every task needs a definition of done that is checkable: row counts, file presence, quality gate pass, pipeline status, semantic refresh state. "It ran" is not a contract. Partial success without a named gate is how gold tables get refreshed from incomplete silver. Put the gate in the DAG where it is visible, not only in a notebook comment. Figure 4 is the contract that matters most between the planes.&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F1-fabric-airflow%2Fterminal-state-contract.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F1-fabric-airflow%2Fterminal-state-contract.svg" alt="Trigger acceptance versus waiting for Fabric terminal state" width="960" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 4. HTTP 200 from the trigger is not done. Wait for Fabric terminal state, then mark the Airflow task success or fail.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Retries that match the failure type
&lt;/h3&gt;

&lt;p&gt;Transient platform blips deserve automatic retry with backoff. Bad data and broken schemas do not. Treat validation failures as terminal for that run unless you have a deliberate quarantine path. Blind retries on quality failures burn capacity and hide the real incident under a green looking retry storm.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Observability that names the step
&lt;/h3&gt;

&lt;p&gt;Operators, run ids, and alert text should point at the failing Fabric artifact and the DAG task in the same message. A ping that says "pipeline failed" without the task id and the Fabric run url forces people to reconstruct context under pressure. Design the alert as part of the DAG, not as an afterthought in a shared mailbox rule.&lt;/p&gt;

&lt;p&gt;Figure 5 is the monitoring surface that makes that contract readable: task id, operator, status, and duration for a Fabric item run. When the DAG waits for terminal state, this view and the Fabric run history should agree.&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%2Feqtheh01al9p03m6t9df.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%2Feqtheh01al9p03m6t9df.png" alt="Fabric Airflow tasks view showing a succeeded FabricRunItemOperator notebook run" width="800" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 5. Tasks view for a Fabric item run: task id, operator, status, and duration in one place. Source: &lt;a href="https://learn.microsoft.com/en-us/fabric/data-factory/apache-airflow-jobs-run-fabric-item-job#monitor-your-dag" rel="noopener noreferrer"&gt;Microsoft Learn: run a Fabric item using Apache Airflow (Monitor your DAG)&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Environments as parameters, not forks
&lt;/h3&gt;

&lt;p&gt;Dev, Test, and Prod should be the same DAG shape with different Fabric targets, identities, and schedules. Copy pasted DAGs per environment drift on the first hotfix. Parameterize workspace, lakehouse, and connection ids the same way you would parameterize a Fabric deploy. Pretty names change. Ids should be the contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Orchestrator does the transform.&lt;/strong&gt;&lt;br&gt;
Airflow notebooks or Python operators slowly recreate what Fabric already owns. Now you have two places to patch logic and no single owner. Figure 2 exists so you do not take that path by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;One fat task for the whole medallion path.&lt;/strong&gt;&lt;br&gt;
Failure at gold forces a full rerun from bronze. Time and cost explode. Partial recovery becomes folklore. Figure 3 is the blast radius made visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hidden dependencies outside the DAG.&lt;/strong&gt;&lt;br&gt;
A semantic model refresh that someone runs after lunch is still a dependency. If it is not in the graph, on-call will learn about it from a broken report, not from Airflow.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Success means HTTP 200 from a trigger.&lt;/strong&gt;&lt;br&gt;
The trigger accepted the job. The job later failed. Your DAG already moved on. Wait for terminal state, or you will publish lies. Figure 4 is the weak contract versus the strong one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Secrets and identities living in two places.&lt;/strong&gt;&lt;br&gt;
Airflow connections and Fabric workspace identities disagree. Runs work on one laptop schedule and fail in the shared environment. Centralize how service principals and key vault references are bound.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alerts without a step name.&lt;/strong&gt;&lt;br&gt;
A mailbox ping that cannot name the DAG task and the Fabric run leaves people reconstructing context under pressure. Figure 5 is the minimum surface the alert should point back to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use as-is or adapt
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use as-is&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fabric owns data plane work; Airflow owns schedule, dependency, retry, and alert contracts.&lt;/li&gt;
&lt;li&gt;Tasks are single-purpose and named for the pipeline step, not for the tool call.&lt;/li&gt;
&lt;li&gt;Terminal state of the Fabric job is the task success condition, not trigger acceptance.&lt;/li&gt;
&lt;li&gt;Quality gates are explicit DAG tasks with defined fail behavior.&lt;/li&gt;
&lt;li&gt;Environment targets are parameterized; no forked DAGs per stage.&lt;/li&gt;
&lt;li&gt;Alerts include DAG task id, Fabric run url, and the artifact that failed.&lt;/li&gt;
&lt;li&gt;No transform logic duplicated into Airflow operators without a written exception.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Adapt before you use&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Airflow adds another runtime to operate: workers, schedulers, package versions, and network paths into Fabric APIs. That cost is real. For a single nightly notebook with no dependents, Fabric native scheduling may be enough. Reach for Airflow when cross-job dependencies, shared SLAs, or multi-system coordination show up.&lt;/p&gt;

&lt;p&gt;You will also negotiate ownership. Platform teams often want Fabric-native orchestration. Data engineers often want DAG readability and ecosystem operators. Pick based on the dependency graph you must explain, not on which demo looked smoother in a workshop.&lt;/p&gt;

&lt;p&gt;API throttling matters when many DAGs poke the same Fabric environment. Set concurrency limits before you scale hourly jobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related
&lt;/h2&gt;

&lt;p&gt;A good next read once the orchestration contract is honest: lakehouse topology choices. Start with &lt;a href="https://www.geekindata.com/blog/8-one-lakehouse-schemas-vs-many" rel="noopener noreferrer"&gt;One lakehouse with schemas vs many lakehouses&lt;/a&gt; when workspace and schema boundaries are the next decision.&lt;/p&gt;

&lt;p&gt;Primary references: Microsoft Learn on &lt;a href="https://learn.microsoft.com/en-us/fabric/data-factory/" rel="noopener noreferrer"&gt;Fabric Data Factory and pipelines&lt;/a&gt;, &lt;a href="https://learn.microsoft.com/en-us/fabric/data-engineering/how-to-use-notebook" rel="noopener noreferrer"&gt;notebooks in Fabric&lt;/a&gt;, &lt;a href="https://learn.microsoft.com/en-us/fabric/data-factory/apache-airflow-jobs-run-fabric-item-job" rel="noopener noreferrer"&gt;run a Fabric item using Apache Airflow&lt;/a&gt;, and Apache Airflow docs on &lt;a href="https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/dags.html" rel="noopener noreferrer"&gt;DAGs&lt;/a&gt; and &lt;a href="https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/tasks.html" rel="noopener noreferrer"&gt;tasks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Workload. Schedule. Contract. Three concerns. Two tools. One readable DAG.&lt;/p&gt;

</description>
      <category>fabric</category>
      <category>airflow</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>Fabric or Databricks? How I Decide</title>
      <dc:creator>Sai Prudhvi Neelakantam</dc:creator>
      <pubDate>Fri, 13 Nov 2026 08:56:20 +0000</pubDate>
      <link>https://dev.to/geekindata/fabric-or-databricks-how-i-decide-2ji3</link>
      <guid>https://dev.to/geekindata/fabric-or-databricks-how-i-decide-2ji3</guid>
      <description>&lt;p&gt;I used AI tools to help draft and edit this post. I checked the facts and the wording, and the original lives at &lt;a href="https://www.geekindata.com/blog/51-fabric-or-databricks-decision" rel="noopener noreferrer"&gt;geekindata.com&lt;/a&gt;. The diagrams are on that page.&lt;/p&gt;

&lt;p&gt;Not a feature war. Five questions I ask before choosing Fabric, Databricks or both, where each choice bites a year later, and when both is honest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Both platforms can run a medallion lakehouse. Feature lists rarely decide; people, consumers, governance and the billing model do.&lt;/li&gt;
&lt;li&gt;If Power BI is the main consumer and the team thinks in SQL and reports, Fabric starts ahead. If the team ships code with tests and CI, Databricks does.&lt;/li&gt;
&lt;li&gt;A Fabric capacity is shared. A heavy background job can push report users into delays and rejections.&lt;/li&gt;
&lt;li&gt;Databricks scales to zero, but someone has to own compute policies, or the bill spreads across many small decisions.&lt;/li&gt;
&lt;li&gt;"Both" works when each table has one owner and data flows one way. A mirrored catalog does not carry Unity Catalog grants.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clients rarely ask which platform has more features. They ask which one they will regret less. The honest answer depends less on the platforms than on the people who will run the thing in its second year.&lt;/p&gt;

&lt;p&gt;I deliver on both. The medallion patterns I use, SCD2 history in bronze, current-row silver, dimensional gold, look the same on each. What changes is everything around them: who writes the code, how it deploys, who governs access, and how the cost behaves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Named model: five questions, in this order&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;People: who builds and runs it in year two?&lt;/li&gt;
&lt;li&gt;Consumers: what reads the gold layer, and is that Power BI?&lt;/li&gt;
&lt;li&gt;Footprint: where does the data already land, and what is already governed?&lt;/li&gt;
&lt;li&gt;Cost: a shared capacity you reserve, or compute you pay for per use?&lt;/li&gt;
&lt;li&gt;Edge: is there streaming or machine learning that sets the bar?&lt;/li&gt;
&lt;/ol&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F51-fabric-or-databricks-decision%2Ffive-questions-tilt.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F51-fabric-or-databricks-decision%2Ffive-questions-tilt.svg" alt="Five questions, each tilting toward Fabric or Databricks: a BI-first team versus an engineering team, Power BI as main consumer versus many consumers, sources landing in Microsoft services versus an existing Unity Catalog setup, steady predictable load versus spiky jobs, report-led real-time versus code-first machine learning" width="960" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1. Each question tilts; none decides alone. Two strong tilts in opposite directions is the signal for both.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Context and constraint
&lt;/h2&gt;

&lt;p&gt;This is a framework, not a scorecard. I do not weight the questions or add them up; I look for the one or two that are not negotiable for this client, and let those lead. Product status below is as of October 2026, with Learn links where it matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. People: who runs it in year two
&lt;/h3&gt;

&lt;p&gt;Fabric lowers the entry bar: pipelines, Dataflows, notebooks and Power BI in one workspace and one place to look. That is a real advantage for a team of BI developers and analysts. The bite comes later: low-code workspaces grow fast and deploy badly unless someone brings Git discipline early.&lt;/p&gt;

&lt;p&gt;Databricks assumes engineers: code in a repo, bundles, tests, a pipeline. Hand that to a team without engineers and it does not get simpler, it gets abandoned, and notebooks get edited in the workspace.&lt;/p&gt;

&lt;p&gt;So my first question is not about data at all: who on the client side can review a pull request?&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Consumers: is Power BI the point?
&lt;/h3&gt;

&lt;p&gt;In most of my projects, Power BI is where the business meets the data, whichever platform sits underneath. If it is the main consumer, Fabric removes a hop: Direct Lake reads Delta tables in OneLake without an import refresh, and the semantic model lives next to the data.&lt;/p&gt;

&lt;p&gt;Databricks data can still reach Direct Lake. A &lt;a href="https://learn.microsoft.com/en-us/fabric/mirroring/azure-databricks" rel="noopener noreferrer"&gt;mirrored Azure Databricks catalog&lt;/a&gt; in Fabric is generally available: Fabric mirrors the catalog structure, reads the tables through shortcuts without copying them, and you can build Direct Lake reports on it. Changes can take seconds to minutes to appear. Plan for two prerequisites: the &lt;code&gt;EXTERNAL USE SCHEMA&lt;/code&gt; privilege on the Unity Catalog side, and network access from Fabric to the storage account behind the catalog (&lt;a href="https://learn.microsoft.com/en-us/fabric/mirroring/azure-databricks-tutorial" rel="noopener noreferrer"&gt;tutorial&lt;/a&gt;). Publishing a catalog to OneLake from the Databricks side is a second route, still in Public Preview (&lt;a href="https://learn.microsoft.com/en-us/azure/databricks/partners/bi/fabric" rel="noopener noreferrer"&gt;Fabric with Azure Databricks&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;If the gold layer also feeds applications, APIs, other teams' notebooks and models, Power BI is one consumer among many and stops being the deciding factor.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Footprint: what is already governed
&lt;/h3&gt;

&lt;p&gt;Where the data lands today matters more than where it could land. A client with an existing Unity Catalog setup, groups and grants already in place, should not rebuild that governance in another product to save a hop for reports. A client whose sources already land in Microsoft services, with no lakehouse yet, has nothing to migrate away from.&lt;/p&gt;

&lt;p&gt;The bite is governance in two places. Unity Catalog grants do not travel with a mirrored catalog: the same tutorial tells you to set access in Fabric's own permission model, and tables with row filters or column masks are not mirrored at all (&lt;a href="https://learn.microsoft.com/en-us/fabric/mirroring/azure-databricks-limitations" rel="noopener noreferrer"&gt;limitations&lt;/a&gt;). On the Fabric side, OneLake security is generally available, but its roles do not restrict workspace Admins, Members and Contributors (&lt;a href="https://learn.microsoft.com/en-us/fabric/onelake/security/table-column-row-security" rel="noopener noreferrer"&gt;OneLake row and column security&lt;/a&gt;). Workspace roles are a security decision, not a convenience.&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%2Fql67z2jjprdub2kqjjyn.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%2Fql67z2jjprdub2kqjjyn.png" alt="OneLake security role demoreaders on a lakehouse: Read permission, type Grant, with the dbo schema as the data in the role" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2. The OneLake role grants Read on one schema, and it is set on the lakehouse rather than the workspace.&lt;/em&gt;&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%2Frwzegj4rongez2gmz5b7.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%2Frwzegj4rongez2gmz5b7.png" alt="Members in role tab of the demoreaders OneLake role, with one user added by email and the name masked" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3. Members are added to the OneLake role separately from workspace access, and workspace Admins, Members and Contributors are not restricted by it.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Cost: reserved and shared, or per use
&lt;/h3&gt;

&lt;p&gt;No numbers here, because they age badly and depend on your agreement. The shapes are what matter.&lt;/p&gt;

&lt;p&gt;A Fabric capacity is reserved compute shared by every workload on it. Smoothing spreads background jobs over the next 24 hours, which makes steady loads pleasant. Overuse it, though, and Fabric first delays and then rejects interactive requests, and report users are the interactive requests (&lt;a href="https://learn.microsoft.com/en-us/fabric/enterprise/throttling" rel="noopener noreferrer"&gt;throttling&lt;/a&gt;). One oversized nightly job becomes a morning of slow reports. Separate capacities, or &lt;a href="https://learn.microsoft.com/en-us/fabric/data-engineering/autoscale-billing-for-spark-overview" rel="noopener noreferrer"&gt;on-demand billing for Spark&lt;/a&gt;, which takes Spark off the capacity, are the usual fixes.&lt;/p&gt;

&lt;p&gt;Databricks bills compute as it runs, and idle compute can cost nothing. That suits spiky loads. The bite is ownership: without compute policies, auto-termination and tags, the bill is the sum of many small choices nobody reviews.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Edge: streaming and machine learning
&lt;/h3&gt;

&lt;p&gt;Both platforms stream and both do machine learning. The question is how deep. Code-first ML with its own lifecycle, feature pipelines and model serving leans Databricks. Event data that business users explore and alert on leans toward Fabric's Real-Time Intelligence. If neither is on the roadmap, do not let a hypothetical one pick the platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. When the honest answer is both
&lt;/h3&gt;

&lt;p&gt;Two strong tilts in opposite directions, for example an engineering team with an existing Unity Catalog setup and a business that lives in Power BI, usually mean both. The pattern I trust: Databricks owns engineering and the tables; Fabric mirrors the gold catalog and owns semantic models and reports.&lt;/p&gt;

&lt;p&gt;It works if three rules hold. Each table has one owner and one writer. Data flows one way per layer. And access is designed twice on purpose: Unity Catalog for the engineering side, Fabric permissions and OneLake security for consumers, reviewed together.&lt;/p&gt;

&lt;p&gt;The reverse direction exists too. Azure Databricks can read Fabric Lakehouse and Warehouse tables through &lt;a href="https://learn.microsoft.com/en-us/azure/databricks/query-federation/onelake" rel="noopener noreferrer"&gt;OneLake catalog federation&lt;/a&gt;, read only, with several Fabric tenant settings to enable. Writing from Databricks into OneLake through an &lt;a href="https://learn.microsoft.com/en-us/azure/databricks/connect/unity-catalog/cloud-storage/external-locations-onelake" rel="noopener noreferrer"&gt;external location&lt;/a&gt; is in Beta, and Learn warns that any non-viewer in that Fabric workspace can read, write and delete the data. I would not build a two-way flow on that yet.&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F51-fabric-or-databricks-decision%2Fboth-one-way-flow.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F51-fabric-or-databricks-decision%2Fboth-one-way-flow.svg" alt="Both platforms together: Databricks owns ingestion, engineering and Unity Catalog; Fabric mirrors the gold catalog through shortcuts and serves Direct Lake semantic models and reports; OneLake federation lets Databricks read Fabric tables read only; access is designed separately on each side" width="960" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 4. One owner per table, one direction per layer, two permission models designed on purpose.&lt;/em&gt;&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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F51-fabric-or-databricks-decision%2Fwhere-it-bites.svg" 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%2Fwww.geekindata.com%2Fassets%2Fblogs%2F51-fabric-or-databricks-decision%2Fwhere-it-bites.svg" alt="Where each choice bites a year later: Fabric workspaces sprawl without Git discipline, shared capacity throttles reports, workspace roles bypass OneLake roles; Databricks setups stall without engineers, compute bills fragment without policies, Direct Lake needs a mirroring hop; both together duplicate governance and add sync latency" width="960" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 5. Pick the bites you can staff for.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Choosing by feature list. Both have the feature; the question is who will run it.&lt;/li&gt;
&lt;li&gt;One capacity for engineering and reports. The nightly job slows the morning.&lt;/li&gt;
&lt;li&gt;Databricks with no engineers. It ends up as edited notebooks and an unowned bill.&lt;/li&gt;
&lt;li&gt;Assuming mirrored means governed. Unity Catalog grants stay behind; masked tables do not mirror.&lt;/li&gt;
&lt;li&gt;Workspace Contributor as a convenience. It bypasses OneLake security roles.&lt;/li&gt;
&lt;li&gt;"Both" without table ownership. Two writers, two truths.&lt;/li&gt;
&lt;li&gt;Letting a future ML project decide today. Decide on what is on the roadmap.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use as-is or adapt
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use as-is&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The five questions, people first.&lt;/li&gt;
&lt;li&gt;One owner and one writer per table when you run both.&lt;/li&gt;
&lt;li&gt;Separate heavy engineering from report capacity, or take Spark off it.&lt;/li&gt;
&lt;li&gt;Designing access on each side explicitly, never assuming it carries over.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Adapt before you use&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The order of consumers and footprint, when what already exists is large.&lt;/li&gt;
&lt;li&gt;How you split capacity, by workload or by environment.&lt;/li&gt;
&lt;li&gt;Whether reports read a mirrored catalog or a copied gold layer, given sync latency and the row filter and column mask limits.&lt;/li&gt;
&lt;li&gt;Whether you need the reverse flow at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;The Fabric and Databricks demo objects for this post are in my public tech-demos repo, with a bundle and a compute policy you can deploy to rebuild the Databricks side.&lt;/p&gt;

&lt;p&gt;Pick the platform your team can run, then design the seams on purpose.&lt;/p&gt;

</description>
      <category>fabric</category>
      <category>databricks</category>
      <category>dataengineering</category>
      <category>powerbi</category>
    </item>
  </channel>
</rss>
