Imagine you have a dataset.
Property records. USPTO Data. Geospatial satellite imagery. Whatever.
You want to put a search box on it.
The normal thing to do is load it into a database, and then add a backend function to allow a user to query it.
That works!
But… now you have a database. You pay $30/month to host it, even if nobody uses it. Or, if it’s big, maybe $150/month. Or you can put it in “bigquery” (for free), but then pay to query it (a lot).
So I don’t use a database anymore.
I use a “lake” now. That’s a buzz-word for an indexed set of files that sit in object storage, usually in a format called “Parquet”.
Parquet has columns, row groups, metadata, indexes, offsets and statistics.
The basic rule is: Query cost is not proportional to total lake size. It is proportional to the amount of metadata and data the query has to touch. So if your user is in Belize, and wants a local map, you’re only querying that one geospatial region… a small fraction of the lake. So it’s fast, and cheap.
Basically.. if you want 50 results, you should not load the entire dataset into memory, and there’s no good reason for you to pay like you did.
DuckDB is the king of reading from data lakes. It allows fast queries and is a full analytics console. But it’s heavy, runs locally, and if you try to put a server in front of it, you’re back to paying monthly server fees.
LakeQL lets you store your data in cheap object store, often below free tiers. Like R2 or S3. And, without a server, query it from edge workers, or in the browser. Because it’s a tiny typescript lib that beats other “embedded wasm analytics systems” for speed on just about every edge query or browser query.
So instead of:
upload CSV
import database
host database
query database
pay database bill
You do:
write Parquet
upload to R2
query from Worker (private data) or Browser (public data)
The user’s machine does the filtering. Your server does nothing.
A user types a zip code. A dashboard loads the last 100 matching records. A map wants all parcels in a bounding box. A public data page wants to sort and filter filings. A customer wants to download a small CSV slice.
None of those should require a monthly warehouse fee.
Example Worker:
import { createLake, r2Store, eq } from "lakeql/cloudflare";
export default {
async fetch(req, env) {
const url = new URL(req.url);
const state = url.searchParams.get("state") || "CA";
const lake = createLake({
store: r2Store(env.DATA),
budget: {
maxOutputRows: 100,
maxConcurrentReads: 4,
maxRangeRequests: 64,
},
});
const rows = await lake
.path("properties.parquet")
.select(["parcel_id", "address", "city", "state", "assessed_value"])
.where(eq("state", state))
.limit(100)
.toArray();
return Response.json(rows);
},
};
A lot of “serverless” systems still leave you paying for a thing that behaves like a server.
The obvious objection is that this is not a real database.
Correct.
It is not for writes. It is not for transactions. It is not for arbitrary joins over huge tables. It is not for unbounded SQL from strangers on the internet.
It is for the much dumber and much more common case:
I have data. I want a small slice. I want it fast. I don’t want to operate a database.
For that, R2 plus Parquet plus lakeql is enough.
Check out https://lakeql.com/. Yes, it’s fully open source. No, there’s no sneaky fee to use it.


