返回资讯中心
外部精选
软件工程
#社区热议

Can we replace a $150k Looker with a bucket of HTML files?

Like a lot of companies, we pay for Looker. Let’s say $150k a year, the average Looker licence1, roughly 300 seats. We are 3 data platform engineers at a company of about 500 people, and most of our week goes on the ung…

Hacker Newsskadamat2026/10/23 · 3 天前30 分钟阅读

以下正文同步自 Hacker News,版权归原站所有,已转换为易读排版。

Like a lot of companies, we pay for Looker. Let’s say $150k a year, the average Looker licence1, roughly 300 seats. We are 3 data platform engineers at a company of about 500 people, and most of our week goes on the unglamorous stuff: keeping Snowflake fed, babysitting a dbt project that passed 2,000 models a while ago, and running the Airflow, Airbyte, DataHub and Kubernetes plumbing underneath it all.

In February, one of us built a thing on the side to host HTML files. It took an afternoon. 8 months later, and it’s already got as many weekly users as Looker in our company, maybe even more and Looker’s down a third.

Tech influencers keep posting about software being dead, and some say they’ve cancelled and vibecoded all their SaaS subscriptions. They say AI is going to kill B2B SaaS.2

SaaS is dead, apparently, so can we replace our enterprise BI tool?

Left: share of new GitHub repos described as "self-hosted". Right: share of Hacker News comments saying "slop".3

A year ago I thought most AI output was slop, and most of it was. We made a few “chat with your data” demos, and they looked great on a toy schema with 4 tables, but never really worked at our scale. The SQL ran without errors, but the numbers were wrong. That’s much worse.

Then Claude Code with Opus 4.5 got really good. Like, really good. In early January adoption across the company skyrocketed. It could work in our repos and use our tools. Also, it could run a query to check the numbers before answering. That mattered a lot more than getting a clever-sounding response. Within a few weeks, people in finance, ops and marketing who had never opened a terminal were prompting all day. All of a sudden everyone was prompting, and nobody was clicking.

One day Maddy from our team said she’d just put them all on a web server, with an internal domain name. By the end of the day she had vibe-coded the whole thing: a small service that stored the files in S3, SSO in front of it, and (some) tests. We already run everything on Kubernetes, so deploying a service was mostly a matter of adding a Terraform module and a Helm chart. Having all that plumbing in place made the whole thing much easier.

She wrote a small Python script and packaged it in a Claude plugin. Users would get their Claude to write the HTML, the script would push it (behind SSO), and anyone in the company could open the link. Initially, the files were just plain, static HTML. In March we thought, why not, and added a live query API using the viewer’s Snowflake OAuth token: best decision of the year.

Turns out, we didn’t need to write a permission model. Snowflake already had one all along. It had roles we’d been maintaining for years, and if Snowflake says you can’t read the sales table, then neither can the dashboard. By April, Snowflake OAuth was the only login.

A Looker tile is a box with a fixed list of chart types and a fixed set of colours, and it looks like every other Looker tile ever made. Ugly, and no personality.

Free-form LLM-generated HTML in less than 1 minute

By getting rid of the rigid fixed tiles, our users could produce free-form HTML and prompt it until it looked neat. They loved it. Email and Slack exports came in April, parameters in May, and weekly viewers went from 23 in March to 136 in June. The exec team started to send links around. People also made the tool their own. They found use cases we would never have thought of, set dashboards to regenerate themselves on a schedule, added buttons, and built some wild designs and UX that no BI tool would have let them.

Security, at this point, was bad. Like, really bad. Dashboard JavaScript ran on the same origin as your session, nothing had permissions, and every employee could read every dashboard. It was basically one big XSS hole: any dashboard could run code as whoever opened it and pull data out in their name. We knew, and we shipped it anyway, because it was internal, behind VPN and SSO, and nothing else did this job.

You"make me adashboard of X"The data-viz skillour templates, chart rules, how to publishUSESClaudelooks at the data,writes the pageOne HTML filecharts + JS + the SQLOur platformhosts the page,runs the queriesA colleagueopens the linkThe dashboardruns in their browserSnowflakeruns the SQL as themASKSWRITESPUBLISHOPENS"GIVE ME THE DATA"AS THE VIEWERROWSClaude writes the page, the platform hosts it, queries run as the viewer.

OK, let’s do it properly

In our team, “let’s just build a BI tool” became a running joke. It stayed a joke for a few months, until it became clear we were in too deep. We had piled months of vibe-coding onto something with a security model we weren’t proud of, and half the company was using it. We stopped joking and said it properly: let’s build a BI tool. We got in front of a whiteboard, mostly to work out how to fix the security model, and to agree on what we didn’t want to lose: the same S3 bucket, no migration, nothing breaking for the people already using it, and publishing that stayed as easy as before.

The one thing everyone agreed on: anyone can still push any HTML in one prompt, with no review step, no template and no list of approved widgets. We’d still defend that.

Every constraint you put between people and their dashboard sends them back to the Downloads folder.

One connector instead of a script. The upload script had been copied into 2 repos and a plugin, and every copy was a bit different. We replaced all of them with one remote MCP connector for the whole company, so claude.ai, Claude Code, Claude in Slack and our own analyst agent all call the same tools. The connector passes your Snowflake token along, and the API checks who you are with SELECT CURRENT_USER(). Whatever an AI uploads lands as a draft, and a human has to click Publish.

Anyone"make me adashboard of X"Claudechat · Code · Slack· agents · CIConnectorone MCP serverfor the whole orgAPIdraft → you click PublishS3filesPostgresversions, grantsSnowflakeknows who you areASKSMCPYOUR TOKENFILESMETADATAWHO ARE YOU?Claude writes the dashboard; the person who asked owns it, under their own Snowflake identity.

Assume every dashboard is hostile. This is the part we needed to actually think about. The whole product is basically XSS by design: anyone can upload JavaScript that runs in a colleague’s browser, nobody reviews it, and the colleague might be the CFO. We can’t block the XSS, because the XSS is the product, so our job is to make sure it can’t reach anything. Our security model starts with “We assume it is hostile” for that reason. Each dashboard runs in a sandboxed iframe on its own origin, which gets no cookies and a strict CSP. The only thing it can talk to is the parent page, through postMessage, and the parent checks who sent the message, attaches the session and calls the API. Content tokens last an hour and work for one dashboard, one viewer and one host.

your colleague's browserSANDBOXThe dashboardwritten by Claude,trusted by no oneno cookies · strict CSPThe shellholds your session,checks who is askingAPImay you seethis dashboard?Snowflakeruns the SQL as you,your roles decidePOSTMESSAGEROWS+ YOUR SESSIONAS YOUDashboard code never touches a credential, and every query runs as the person looking at it.

The sandbox protects the browser. We also created a separate metadata service that reads every new version of a dashboard async. It pulls out the whole HTML and the Snowflake queries. It checks for the scripts the page loads and where it sends data. Then a set of rules judges those facts. Most rules only report. They flag a dashboard that reads raw data instead of a dbt model, a script that isn’t pinned to a version, or a dashboard nobody has opened in 90 days. Some rules can block a dashboard: a script from a package nobody here has used before, or a WebRTC connection, which is the one way out that CSP can’t block. A blocked dashboard doesn’t load. The viewer sees a warning and has to accept it before the page runs.

APInew versionpublishedQueueMetadata serviceWHAT IT DOES· tables it queries· scripts it loads· where it sends datastored once per versionEVENTRULES!Reporta flag the author can see✕Blockviewer gets a warningbefore the page runs✓Reviewedchecked by the platform,not by a persononce a day: has anyone opened it in 90 days?Checks run after publish, so nobody waits for them.

Let Snowflake do identity and permissions. Every query runs with the viewer’s own token. Sharing a dashboard never shares data access. That’s a security feature, and it’s also a laziness feature: we never had to build or maintain data permissions, because everyone who logs in already has a Snowflake user with the right roles.

Content management. This part we vibe-coded in about a week, and it barely needed any design. For spaces, folders and sharing we copied Google Drive, because everybody already knows how Google Drive works: viewer, editor and owner, grants flow down the folder tree, and the strongest grant wins. Versions are stored by content hash, and restoring one gives you a draft. Then search, likes, scheduled exports, and teams synced from the HR system every hour. Compare that with the security model, which is where nearly all the real thinking went.

It took a few weeks of dev, and we got there.

Then it spread. People started tagging Claude in Slack threads and getting a dashboard back. Our analyst agent publishes its own, some repos publish straight from CI, and most people just publish from their own Claude, so every dashboard ends up looking a bit like the person who made it. These days it’s everywhere.

That’s the whole bill on our side: 8 months, 3 engineers doing it on the side, plus a few friends who sent PRs. Claude wrote most of the code. We did the whiteboarding, argued a lot, and reviewed everything.

Looker’s usage leaked rather than crashed. We haven’t moved everything: some teams still live in Looker, and some of its dashboards have no replacement yet. What made people use this instead of Looker is that building a dashboard stopped being expensive. That made us curious: how cheap, exactly? The good thing about paying in tokens instead of engineering time is that it’s easier to measure.

We use our analyst agent as a proxy here, because it’s a builder we can measure exactly. Every run is logged with its tokens and its cost, and every publish links back to the run that made it.

We found that each dashboard takes the agent around 1 million tokens, from the first question to the finished page. Now that we’ve moved it to Opus 5.5, the cost of a dashboard has dropped from about $2.50 to about $0.50. The agent does the same work; the tokens just got cheaper. That’s the real story: building software now costs whatever tokens cost, and that price keeps falling.

Here’s the bill for the whole thing, from the first commit in February to now.

Running it costs about $6k a year in AWS now that it has its own database, plus whatever Claude we spend to keep adding features, which has been around $1.3k a month since July. Call it $20k a year, against $150k for Looker, and most of that $20k is us building new stuff rather than keeping the lights on.

When we bought Looker we were buying 4 things: a UI to draw charts, a permission model, a semantic layer, and somewhere to host it. Claude now draws the charts, one dashboard at a time.

Take those away and what’s left is a $150k invoice.

We’re not the only ones, either. You hear it more and more often: solid, established businesses cancelling very expensive analytics subscriptions. Amjad Masad told Platformer the same story about Replit: once he could join the warehouse to production Postgres and build the report himself, they “canceled or downsized most of [their] analytics products”.

In our case, building a dashboard tool around our existing stack has cost a fraction of what we were paying for Looker. For us, the important bits were already in dbt and Snowflake: the models, permissions and data. Looker sat on top of

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →