Engineering

5 MIN READ

The GraphQL Lesson BI Never Learned

GraphQL let app developers get the data they needed without filing a ticket with the backend team. Business users never got that. They still wait in line for someone to build their dashboards. An agent working from a data model that defines every number once lets them skip the line.

Nathan Huff

Nathan Huff

Head of AI & Application Development @ Credible · Sep 29, 2026

GraphQL caught on because it let app developers get the data they needed without asking the server team for every change. BI never found a way to give business users the same leverage.

In 2012, Facebook was rebuilding its iPhone and Android apps, starting with News Feed. The app developers knew exactly what data each view needed, but the server's APIs returned data in a different shape. Getting the right data took extra server code to package it, extra app code to unpack it, and new server work every time a view changed.

GraphQL split the work differently. The server team published a schema, a list of all the data the apps could ask for. App developers wrote their own queries against the schema and asked for exactly the fields they needed. The server still decided what each app was allowed to see. Most changes to a view no longer needed new server work. Adding a field didn't break any app already using the schema, so there was no new API version and no forced update. Each app started using the new field when it was ready.

But GraphQL only helped people who write code. At Amazon, I built a GraphQL API over all the analytics data in the Devices org, so anyone could ask for exactly the data they needed. Almost nobody did. Most of the people who needed that data didn't write queries, so they kept asking engineers to pull it for them.

An agent can write the query for them.

Dashboards have the same problem

Business users know exactly what they want to see, but they don't write queries and can't build dashboards themselves. So they ask someone who knows the dashboard tool, and they wait.

BI's version of the problem is worse. Each team finds whatever help it can to get its numbers, and each team decides for itself what "revenue" means.

The fix has two parts. An agent builds the dashboard for the person who asked. I made that case in Dashboards Aren't Dead. WYSIWYG Builders Are. The agent also builds every dashboard on one data model that defines each number once. Kyle made that case in The Semantic Layer Is an Interface, Not a Compiler. Together, the two parts give business users what GraphQL gave app developers: a list of the data they can ask for, and a way to ask without waiting on an engineer.

A dashboard works like a GraphQL app

In our setup, a dashboard is a data app: a plain web page served from a Malloy package. Every number on the page comes from one call, Publisher.query(modelPath, malloyQuery), against the data model in the same package. This works like GraphQL in three ways.

First, there's no server code for each dashboard. A GraphQL app doesn't need a new endpoint for each view, and a dashboard doesn't need its own server code. Every chart on every dashboard sends its query through the same gateway. When you add a measure to the data model, every dashboard can use the new measure on its next query.

Second, access rules live on the server. A dashboard can send any Malloy query, and the data model's access rules decide what comes back, based on who is viewing the dashboard. So you don't have to trust the dashboard's code. Curate What Your Agents See explains how to set up those rules, and the access control doc has the details.

Third, the agent reads the data model first. GraphQL lets developers browse the schema, usually with a tool called GraphiQL. An agent does the same with the data model: before writing a query, the agent reads the model's sources, measures, and descriptions, so it only uses fields that exist. The difference is how often. A developer usually checks the schema once and works from memory after that. An agent checks the data model every time.

Where a data model goes further

A data model does two things a GraphQL schema can't.

First, a data model can't drift from what it describes. In GraphQL, each field is backed by server code, and that code can stop matching the schema without anyone noticing. In Malloy, there's no separate code behind a field. When a query asks for a measure, Malloy compiles the measure's definition into the SQL it runs.

Second, a data model says what the data means. Here's a GraphQL type:

type OrderItem {
  id: ID!
  salePrice: Float!
  returnAmount: Float!
}

The type lists three fields and their types. Here's the same data in a Malloy data model:

#(doc) Order line items -- one row per product sold
source: order_items is duckdb.table('items.parquet') extend {
  primary_key: id

  join_one:
    #(doc) Customer who placed the order
    customers with customer_id

  #(doc) Revenue, net of returns
  measure: revenue is sale_price.sum() - return_amount.sum()
}

The GraphQL type tells you salePrice is a number. It can't tell you that revenue is sales minus returns, that each row is one product sold, or how orders connect to customers. That knowledge usually lives in a wiki, in an analyst's head, or nowhere.

The Malloy data model writes that knowledge down, so an agent uses it on every query. GraphQL and Malloy both reject a query for a field that doesn't exist. The data model's joins and measures also prevent mistakes that still run: joining the wrong tables, counting rows twice, or using gross revenue when you meant net. Those mistakes produce wrong numbers, not error messages, and the person reading the dashboard can't tell. In Kyle's example, the same question comes back as $1,445 when the real answer is $955. Kyle's Meaning Is the Product makes the longer case.

Follow-up questions don't need a new dashboard

A dashboard answers the question someone had when it was built. When the number changes, people ask why, and the dashboard doesn't answer that. With a dashboard tool, the new question becomes a new request. With a data model, the new question is just another query.

The agent that built the dashboard can answer the follow-up without changing the dashboard. The agent reads the data model again and writes a new query. That query can use data the dashboard never showed, or break the number down a new way, and still use only the joins the data model defines and the rows that person is allowed to see. The person asking doesn't need to learn Malloy.

Who gets to ask

GraphQL let app developers get their own data. With an agent writing queries against a data model, business users can do the same: ask for a number, ask why it changed, and get it calculated the way the company defines it.

The AI Analytics Engine

Make your data Credible

Model your data's meaning, and the AI Analytics Engine delivers answers you can trust to every agent, data app, and dashboard that asks.

Get started

More from Credible

Engineering

16 MIN READ

Policy Is Prose. Compliance Is Controls.

Agents now do most of the data access in your company. The access policy you already have is the right defense, but only if its rules live where the data is served and an agent checks them on every change. We built a real example on synthetic patient records: a HIPAA-shaped policy, a data model that carries its classes and gates, a server that refuses a model that breaks them, and the evidence an auditor would ask for.

Kyle Nesbit

Kyle Nesbit

CEO & Founder @ Credible

Engineering

11 MIN READ

Materialization Is an Annotation, Not a Pipeline

Materialization in Credible is an annotation, not a pipeline. Mark a source with #@ persist or a measure with #@ preaggregate, and the engine builds the tables, routes queries to them and cleans them up. A missing table makes a query slow, not wrong, and the versioned package is what ships. This post walks through it on Malloy Publisher's storefront example, which you can run yourself.

Girish Jeswani

Girish Jeswani

Software Engineer @ Credible

Engineering

6 MIN READ

Version Control for the People Who Own the Numbers

A data model kept as code, under version control, is the right way to build one. It also left most of the business behind: first the code, then the developer tools. Coding agents and our open-source skills took care of the code. The Credible app takes care of version control, so business and technical people collaborate on the same data model in the tools they each prefer, and ship it together to the agents and apps that run on it.

Nathan Huff

Nathan Huff

Head of AI & Application Development @ Credible