The way your business defines itself - what counts as revenue, which customers are active, how margin is calculated - is written down in one place: your LookML. Your team built it, a definition at a time, over years. And only Looker can read it.
So when you leave Looker, that logic is what you're actually taking with you. The dashboards on top are easy to replace. The definitions underneath are the asset, and they're the thing that's stuck.
That gives you a choice. You can rebuild what you have, screen for screen, and end up where you started in a different product. Or you can use this as an opportunity to build something better: one model of your business that everything draws from - not just the dashboards and questions of today, but the data products and workflows of the future, still to be imagined.
This guide is about how Credible - our team and our product - will get you there.
Why teams leave Looker
In roughly the order they come up:
You still pay by the seat. Every person who wants a number needs a licence, on top of the platform fee. So you do what everyone does and ration seats. But rationing doesn't cut the cost, it just hides it: now the unlicensed majority waits on the licensed few, and you spend half your time denying access you're already paying for. Seats made sense when a report was one person's job. They don't describe how anyone works now.
The model only works well inside Looker. Years of logic sit in LookML, and Looker is the one product built to read it. Embedded analytics and an MCP server exist, but both came later, bolted onto a model designed for Looker's own explores. Everything else - a data app, a finance system, an agent - has to fight to make the numbers match.
Every new question waits in a queue. A field that doesn't exist yet means a LookML change, a review, and a wait on a small team. The people who can't wait export to a spreadsheet and redefine the metric themselves, and one number quietly becomes three. It isn't that the reviewers are slow. There's just more drafting than any small team can keep up with.
You don't really own the model. LookML is text in your git repo, but only Looker can compile it, so the repo is worth exactly what the licence is worth. The roadmap isn't yours either: Looker ships on Google Cloud's schedule, through Google Cloud's support queue. When the surface you need next is an agent or an embedded app, you wait for someone else to decide it matters.
Point an agent at the raw warehouse and it guesses. Sooner or later, someone will. An agent turned loose on raw tables fills the gaps with confident, wrong answers: joins it invented, definitions it guessed, stale numbers it treats as current. The bad answer looks exactly as authoritative as a good one, which is what makes it dangerous.
And when they do, they've gone around everything you built. This is the part that should worry you. The spreadsheet was the old way around the modeling queue; an agent on the warehouse is the new one, and it skips the model entirely. Every definition, every access rule, every bit of governance you put into LookML: bypassed, because the query never went through it. You find out when a wrong or unauthorized number is already in front of someone who matters.
What you get with Credible
The six problems above, fixed.
No seats. Credible doesn't charge per user. Publishing and agent access are free; you pay for what you actually run - tokens, compute, storage. Nobody has to justify a licence to ask a question, and you stop rationing access to manage a bill. The cost tracks usage, not headcount.
One model behind everything you do with data. Dashboards, notebooks, customer-facing apps, internal services, and whatever agent your team uses all draw from the same governed model. The number in a board deck, the number in a customer's portal, and the number an agent quotes come from one definition, so they agree without anyone reconciling them. And because it's one model, the next surface you build is a new view on what you already have, not a new integration.
Changes ship in a pull request, not a ticket. Your coding agent drafts the model change; your data modeler reviews the diff and merges it. The people waiting on a new field get it in hours, and the people accountable for the model still approve everything that ships. The drafting stops being the bottleneck, and nobody gives up control to get there.
A model you actually own. It's plain text in your own repository, in an open language, and it runs against your warehouse - or on its own engine and storage when there's no warehouse yet. Stop paying anyone and it keeps working. No vendor has to compile it for you, and no vendor's roadmap decides what you can do with it next.
Your agent works from the model, not the raw tables. Ask a question and the agent pulls the slice of the governed model it needs - the real definitions, not a guess. It also knows your data's values, not just its field names. Ask for order status complete when every row actually says Complete, and instead of quietly returning zero of 255,883 rows, the agent uses the value that exists and gets it right the first time. The model is what turns a confident guesser into something you can trust.
Your rules travel with every query. Governance lives in the model, not in the tool, so it applies the same way whether the caller is a person, a dashboard, or an agent - resolved from their verified identity, on the server, every time. There is no "around" to go: a query that skips the model doesn't reach the data, because the model is how everything reaches it. Someone the rules don't cover gets nothing back, not a workaround.
None of this needs a big-bang cutover, and it's less work than it looks, because you're not migrating dashboards. You're migrating the domain underneath them, and your LookML is the best record of that domain you have: years of definitions, formulas, join cardinality, and hard-won curation, already written down. We treat it as prior art - not a spec to transpile line for line, but a record of what you meant, to rebuild from as a governed data model in Malloy.
Still weighing it up? Credible vs. Looker puts the two side by side. This guide is for after that.
How the migration works
Here's the whole method. You can run it yourself, or book a call and our solutions engineers do it with you - the survey of your LookML, the conversion, the access-control decisions, and the parity check that proves the numbers still tie out.
The instinct is to count the dashboards, multiply by an hour, and price the project. That number kills it before it starts, and it's measuring the wrong thing. There is never one dashboard - there are dozens or hundreds, uneven in quality and usage, a handful carrying nearly all the traffic. Recreating them tile for tile is the most expensive way to migrate, and it carries your old ceiling across with the content: the same explores answering the same questions in a different product.
So we don't rebuild dashboards. We rebuild the domain underneath them - the fields, metrics, and relationships people actually use - modeled so an analyst or an agent can recreate every tile and answer the follow-up each tile implies. A dashboard is really a list of questions someone already cared about. Those questions are the useful part. What you rebuild is the domain that can answer them, and the next ones too.
Most of your LookML is dead weight
A LookML project that's run for years exposes far more than anyone queries. On a migration we recently ran with a customer - one certified dashboard, 28 tiles, 3 explores - those explores exposed roughly 6,500 fields. A few hundred were in real use. The rest had simply accumulated: fields defined for a report that shipped once, duplicates, things nobody had opened in over a year.
That's the real work of a migration. Not translating fields - finding the few hundred that carry actual business logic and leaving the rest behind. A migration is the only time anyone will have permission to do it.
We find them in three passes:
- Tile references - every field a tile uses in its selects, filters, and sorts.
- Inline measures - the calculations defined on the tiles themselves rather than in LookML, where a surprising amount of real logic hides.
- Ad hoc usage - fields people query on their own that no dashboard touches, plus whatever those fields depend on, so nothing you keep points at something you cut.
On that customer's dashboard, the first pass found 126 fields, the second another 170 defined inline, and after the third pass and the trim, 377 made the cut: a complete, lossless model of the domain, out of the ~6,500 the explores had exposed.
Looker makes the trim defensible, because it already records what people ran. System Activity is Looker's own model of its usage - the History, SQL Query, and Content Usage Explores, among others - so you can rank explores and fields by real traffic and retire the rest on evidence, not opinion.
The five steps
- Pick. The certified dashboard whose tiles span the domain: what stakeholders quote, and what semantic search will be asked to find.
- Capture. Every field referenced by tiles, filters, sorts, and inline measures. What's used, not what's available.
- Survey. Add what people query outside the dashboard, cut everything else, then keep whatever the survivors depend on.
- Model. Base sources first, then domain-joined sources, then reference data. Structure it by question, not by dashboard layout.
- Curate and publish. The last pass decides what an agent meets: named queries for the canonical views, a
#(doc)on every field,#(index)on the dimensions people name by value, access rules where a rule has to hold, and#@ persistwhere a query is expensive. Publishing compiles it and serves it everywhere at once.
32 base sources (one Malloy file per physical table, no joins), 6 domain sources grouped by question - acquisition, revenue, engagement, monetization, lifecycle - and 14 named queries on top. We deliberately avoided a single "everything" source: cross-domain questions get answered by the agent running a few targeted queries, which is cheaper and more accurate than one giant join graph.
What you'll need
Three things. Only the first is required.
Your LookML project - the manifest, model, view, and explore files. The agent inventories them and resolves manifest constants as it goes.
A warehouse connection. This is the one that changes the outcome. LookML tells the agent what a field is supposed to mean; the warehouse tells it whether the translation returns the same number.
Looker API access, optionally - useful for running an original explore and for pulling System Activity over the API. A small MCP server (looker-mcp-server) hands your agent the Looker API as tools, including an audit group that reads query history straight out of System Activity. One thing to check first: a service account has to satisfy each explore's required_access_grants, or restricted explores return a 404 that reads exactly like "explore not found" and needs admin rights to fix. The conversion preflights those attributes, so that dead end arrives as a clear message instead of a run of 404s.
| What you give it | What you get back |
|---|---|
| LookML only | Full translation, every proposal flagged unvalidated |
| LookML + warehouse | Translation validated against live results, row by row |
| LookML + warehouse + Looker API | The above, plus usage-driven trimming and explore-level comparison |
What carries over
The everyday modeling comes across as you'd expect. Here's how the bigger pieces land. Two of them need more than a line and get a section below.
| In Looker | In Credible |
|---|---|
| Views and explores | One Malloy source, joins folded in (relationship: many_to_one becomes join_one) |
| Dimensions and measures | The everyday building blocks, carried over as they are |
| Native and persistent derived tables | #@ persist for the performance-only ones, a query-based source for a real transformation (see below) |
| All three access mechanisms | One #(authorize) rule for two of them; sql_always_where written down rather than migrated (see below) |
hidden: yes | Mapped by reason: a # hidden tag for an intermediate calculation, plain and public for a join key, internal: only where the field is genuinely unused |
fields exclusions | internal: - the field was structurally inaccessible, and stays that way |
description: and labels | #(doc) and #(index) tags, compressed into the engine's concept index |
| Liquid SQL templating | Real typed Malloy expressions, with no SQL strings to template or debug |
drill_fields | Skipped as Looker UI detail. Drilling is added back where it earns its place, as a # drill tag on a model dimension, which makes every result grouped by it clickable in a dashboard or a notebook alike - because it lives in the model, not on a tile |
html:, viz styling | Presentation, so it's dropped. Where one hides a business rule - an html: block flagging margin under 5% - the rule becomes a real field and the styling is left behind |
| Dashboards and Looks | Rebuilt as a dashboard, a notebook where the numbers need prose, or an HTML data app where the design matters - none of them capped at Looker's tile set |
Two more the conversion flags rather than reproduces. Refinements (+view) get consolidated into one definition instead of layered across four files. Synthetic primary keys built from concat() or generate_uuid() get questioned, because that pattern is almost always a workaround for a grain nobody wrote down, and the migration is the moment to fix it.
Derived tables: who owns materialization
Derived tables are where migrations lose logic, because one LookML keyword covers three different things. They get sorted before anything is converted.
| In LookML | What it really is | What it becomes |
|---|---|---|
| Native derived table | A query saved in the model | A query-based Malloy source |
| Performance-only PDT | The base table, plus a build schedule | The base table, plus one annotation |
| Transformation PDT | Joins, CTEs, and computed columns carrying business logic | A query-based source, once someone confirms the logic |
The performance-only case is the easy win. A SELECT * with a generated key, wrapped in partition keys, cluster keys, and a datagroup_trigger, collapses into a single #@ persist on the source. One line replaces the derived table, the datagroup, and the trigger.
The transformation case is the one to handle carefully. Strip a transformation PDT back to its base table and the logic disappears without a trace, so those get flagged for a person to confirm rather than converted on sight. Rewritten as a Malloy source, the transform type-checks, composes, and can be read, instead of travelling as an opaque blob of SQL. A measure that gets hammered can take #@ preaggregate at whatever grain you declare. The transformation keeps running; it just stops being a build schedule you babysit.
When a performance-only PDT stops being a PDT, who runs it? Here the engine does: the annotation declares the intent, and the engine builds the table, refreshes it incrementally, shares it across model versions, and drops it when the last version that needed it is archived. Most tools answer differently - they cache query results and leave heavier materialization to your warehouse or dbt. That's a legitimate design choice; it just means the work moves to a team you have to ask, rather than disappearing.
The engine also brings its own query engine and columnar storage, so you don't need a warehouse to start. The model still compiles to optimized SQL for whatever database does hold your data, and stays locked into none of them.
Access control is not a find-and-replace
Looker has three access mechanisms, and they all look like security. That's the trap. Two of them become the same Credible rule, the third shouldn't be migrated at all, and confusing them is the kind of mistake that stays invisible until it matters.
| In Looker | What it decides | What it becomes |
|---|---|---|
access_grant, required_access_grants | Who may query the explore at all | An #(authorize) rule: every row, or none |
access_filter | Which rows a caller sees | The same rule, reading a column: the rows that caller is allowed |
sql_always_where | Often a data-quality filter, sometimes a real restriction | Never migrated on sight: written down, and re-expressed as a rule only where it restricts |
One subtlety is worth stating plainly, because it's the trap most migrations fall into. A Credible model carries no per-viewer context of its own, so masking a value (everyone sees a banded figure) and controlling whether a caller sees a field at all are separate layers. Confuse them and you ship a model that looks restricted and isn't. That's why every required_access_grants is flagged for a person to rule on rather than converted automatically. The access-control guide has the full mapping and the code.
Where the rules land also changes. Looker's controls protect Looker, so anything reaching the warehouse another way is outside them. Credible's rules run on every query, so the same one covers a workspace, an agent, a dashboard, and an embedded app without being restated in any of them.
Proving the numbers match
No migration is done because the model compiles. It's done when someone trusts the number.
We validate two ways, together. The Looker API runs the original explore and we compare. Or we run Malloy against the same warehouse the explore reads and diff it against the equivalent SQL run directly there - in practice, the channel that does most of the work, with or without API access. Both sides hit the same data, so any difference is a difference in logic. On that customer's migration, every tile we rebuilt came back identical to the original, row for row.
When a delta shows up, we confirm and flag it. We never silently reconcile it. A source of truth carries its own bugs, and a migration that quietly matches them has laundered a bug into a new system. Some of the most valuable findings are the two dashboards that never agreed and nobody had noticed.
You finish with a coverage report: every LookML view and field marked modeled, renamed, rearchitected, deferred, or skipped, each with a reason.
The question your old dashboard couldn't answer
Matching the old dashboard is the least of it. What made this migration worth doing showed up on the first question the dashboard couldn't answer: how net-new customers were pacing against the monthly target. One query against the acquisition domain:
#(doc) Net-new customers, actual against the monthly target.
query: new_customer_pacing is acquisition -> {
group_by: activation_month
aggregate:
actual is total_new_customers
target is targets.value
pace is actual / target
}The old explore couldn't express that question at all. The model can, for three reasons:
The model composes. Malloy views nest, chain, and get reused as sources, so it answers follow-ups the original explore never exposed.
The meaning comes with it. Every field carries its own documentation and indexed values, so an agent finds the right one and uses it correctly instead of guessing from a name.
It can't double-count. Malloy's symmetric aggregates mean a measure won't fan out across a one-to-many join - the bug that silently inflates SQL results and BI extracts simply can't be written here.
Start with one explore
Not the whole instance. Pick the explore behind the dashboard people actually argue about, run the five steps, and compare the numbers. You'll get a real coverage report, a real sense of pace, and a governed model you can point an agent at on day one. That last part is what the old stack could never do, and it's why leaving is worth more than a like-for-like rebuild.
Book a call, read the migration docs, or see how Credible and Looker compare.