Initializing DuckDB...
For the best experience, use a desktop browser with screen width ≥1024px.

DuckDB Playground

// BROWSER-BASED SQL ANALYTICS

A scratchpad for exploring data. Not an analytics platform, not a data warehouse, and not a controlled environment. Files you import are read and queried in this browser tab and are not uploaded. That covers your data and not the code: this page pulls DuckDB, Chart.js, SheetJS and fflate from third-party CDNs at load time. Anything you compute here is exploratory until you reproduce it somewhere accountable. Open for the full scope limits.

What this tool actually does

Runs DuckDB compiled to WebAssembly inside this tab. Files you add are parsed in the browser and registered as tables, queries execute locally, and results are rendered and exported from the same page. There is no account, no server-side query engine and no telemetry.

What "runs in your browser" does not cover

  • The code arrives over the network. DuckDB-WASM, Chart.js, SheetJS and fflate are loaded from third-party CDNs on every visit. Your data stays in the tab; the software operating on it does not come from you, and a substituted script would run with full access to whatever you imported.
  • Anything inside the browser is inside the boundary. Extensions with host access, devtools, and page state recovered by a session restore can all see the tab.
  • Exports leave it. A downloaded CSV, Excel or Parquet file lands unencrypted in your downloads folder, and from there it is an ordinary file subject to sync, backup and search indexing.
  • Local is about transmission, not permission. It says nothing about whether you are allowed to open, join or export the data you just loaded.

Where the answers go wrong

  • Type inference is a guess. Column types are inferred from a sample when a file is imported. A postcode, an account number or a leading-zero identifier read as a number is silently altered before you write a single query.
  • Precision. Large integers and high-precision decimals can lose exactness passing through JavaScript, and a sum that looks right can be off in the last digits.
  • Nulls, blanks and encodings. An empty string, a null and the literal text "NULL" are three different things, and which one you get depends on the file and the parser, not on your query.
  • Silent truncation. Previews and charts show a subset. A result that fits on screen is not evidence the query returned what you think.
  • Memory limits. The whole dataset lives in the tab. A join or an aggregate that exceeds available memory fails, or degrades, in ways a server-side engine would not.

A query that runs is not a query that is correct. Nothing here validates your joins, your grain, your filters or your assumptions about the data.

Never use this for

  • Regulated data on a machine or browser you do not control, including protected health information under HIPAA, cardholder data under PCI DSS, and personal data under GDPR.
  • Financial reporting, reconciliation, tax, audit or any figure that ends up in a statement of record.
  • Regulatory, clinical or compliance submissions, and any analysis that must be reproducible on demand.
  • Production pipelines, scheduled jobs or anything another system depends on.
  • Decisions about people, where a query result becomes a rule.
  • A system of record or a backup. Everything here is gone when the tab closes.

Before an answer leaves this page

Reproduce it against the source system, in a query someone else can run, with the types declared rather than inferred. Check the row counts at each step and confirm the grain of every join. For anything that matters, have the query and the result reviewed by someone who knows the data.

Shift+Enter to run

Results

Exploratory results. Column types were inferred from a sample when the file was imported, previews and charts show a subset, and a query that runs is not a query that is correct. Reproduce anything that matters against the source system before it leaves this page.

Run a query to see results