Build a pipeline, share it as a link
Stack cleaning and reshaping steps in the order you want them, and every change recomputes the whole chain immediately. Each step reports what it did to the row and column counts, so a step that quietly halves your file is visible at the step that did it. Copy a link and the entire pipeline travels inside it, without ever reaching a server.
One file, several problems, in a specific order
Real files are never wrong in only one way. The export has Order ID with a space in it, and padded cells, and day-first dates, and the same row three times, and a blank owner column where somebody left the field empty. Fixing those one tool at a time means five downloads and five uploads, and if you have to do it again next month you get to remember the order.
The order is not incidental. Deduplicating before you trim whitespace misses the duplicates that differ only by a trailing space. Filtering on a date column before you normalize the dates compares strings that are not in a comparable format. Cleaning headers after a step that names a column breaks that step. A pipeline makes the order visible and adjustable, which is most of the value: you can see that trim comes before dedupe, and you can drag it if it does not.
So this is one page holding the whole sequence. The steps run top to bottom, each one taking what the last one produced, and the result at the bottom is the file you download.
No run button, and a count under every step
Nothing here waits for you to press anything. Change a dropdown, type in a box, drag a step to a new position, and the chain recomputes from the top. Text inputs are debounced so it does not thrash while you type, and that is the only concession.
What makes that useful rather than merely responsive is the line under each step:
1. Clean headers 7 headers rewritten · style: snake
2. Trim whitespace 23 cells trimmed · runs of spaces collapsed
3. Remove duplicates 1 duplicate dropped · 7 rows kept · matched on every column
4. Normalize dates 7 dates rewritten · format: iso · columns: close_dateEvery step says what it did in the units that matter for that step. This is the thing that turns a pipeline from a black box into something you can reason about. A dedupe step reporting 4,182 duplicates dropped on a file you thought was clean is a finding. A trim step reporting 0 cells trimmed tells you the whitespace theory was wrong and to look elsewhere. Without the counts you would see only the final row count and have no idea which step accounted for the difference.
A step that fails stops the chain at that point and shows its error in place, so you know which step broke rather than being told the pipeline failed. The steps above it still show their results, because they still ran.
The sixteen steps
Check. Validate reports structural problems and changes nothing: blank or duplicated headers, empty columns, exact duplicate rows, and a completeness percentage. It belongs at the front of a pipeline you are exploring, and at the back of one you are shipping, as a final assertion.
Clean. Remove duplicates with an optional column subset and case-insensitive matching. Filter rows and Sort rows. Clean headers into snake_case, camelCase, Title Case, lowercase or UPPERCASE. Trim whitespace, optionally collapsing internal runs. Fill blanks by carrying values down, carrying them up, writing zero or writing a literal. Find and replace across the file or in one column, with regex. Normalize dates into ISO, US, EU or Unix.
Shape. Select columns to keep or drop. Split a column on a delimiter. Merge columns into one. Calculated column from an expression. Group and summarise. Query with SQL, the escape hatch, running DuckDB over the result so far with the table named csv.
Finish. Split into files is terminal: it takes the result and cuts it into several downloadable files, either by row count or by the values of a column. Anything after it is ignored, because there is no single table left to hand on.
The calculated column, and why it is not eval
The expression step handles arithmetic, comparison, text and conditionals:
price * qty quantity times price
round(price * 1.2, 2) with tax, to the penny
first .. " " .. last joined with a space
if(amount > 1000, "large", "small") a bucket
upper(trim(`Email Address`)) normalized, backticks for spaces
coalesce(nickname, first_name) first one that is not empty
left(order_date, 7) the month, for groupingFunctions include if, round, abs, floor, ceil, min, max, upper, lower, trim, len, concat, left, right, contains and coalesce. Column names with spaces go in backticks. Division by zero produces a blank rather than infinity, which is the honest CSV version of a spreadsheet's error cell.
This is a small hand-written parser, not eval, and that matters because a pipeline arrives as a link from someone else. The parser knows about numbers, strings, column names, the operators above and those sixteen function names, and nothing else. There is no path from an expression in a shared link to the page's JavaScript, to your clipboard, or to a network request. A column lookup reads own properties only, so an expression naming constructor gets an empty cell rather than a JavaScript function.
The competitor's equivalent accepts only + - * / ( ) over numeric columns: no functions, no comparisons, no string concatenation, no conditionals. That is the whole difference between a calculator and something you can build a bucket or a normalized email with.
The link is the pipeline
Copy a link to this pipeline and the entire specification is compressed and encoded into the part of the URL after the #. A four-step chain comes out around 120 characters.
The fragment is the important detail. Browsers do not send it to the server. Not to ours, not to a CDN, not in a redirect. So the pipeline you built, including any column names, filter values and SQL you typed into it, exists only in the link itself and in the browsers of whoever you send it to. There is nothing to store, nothing to delete, and no account to have made.
Your data was never involved. The link carries the recipe, never the file. Send someone your cleaning pipeline and they run it on their own export.
It also means a recipe is editable rather than a contract. Open somebody's link, drag a step, switch one off, add your own, and copy a new link. There is nothing to fork and nothing to ask permission for. The recipes page is sixteen of these written by hand, each one carrying a sample so it produces a result the moment it opens.
Where a pipeline ends
The result at the bottom downloads as a CSV, or as a zip of files if the last step split it. Two other exits are more interesting.
Build a dashboard from this sends the finished result to the dashboard builder. That is the whole point of cleaning something: a chart of the raw export would have counted ACME Corp and acme corp as two customers.
Open in Data Explorer sends the result to the full application, which has the grid, the chart builder, SQL and its own pipeline. Under the button is a line saying how much of your chain has an equivalent there: most steps map exactly onto one of the app's own operations, a few arrive approximately, and two have no equivalent at all. The mapping is written down in src/quickconvert/pipeline/opMapping.ts with a caveat against every partial one, and a test keeps it honest as both sides change.
Whichever exit you take, the transformed data travels rather than the raw file, so you land looking at the result you just built.
Frequently Asked Questions
Where is the run button?
There is not one. Every change recomputes the whole chain, with text inputs debounced so it does not run on every keystroke. On a file of a few hundred thousand rows the visual steps finish in well under a second. The exception is the SQL step, which downloads a 4 MB engine the first time it appears in a pipeline; after that it is fast too.
Does my file get uploaded when I share a pipeline?
No, and neither does the pipeline. The recipe is compressed into the part of the URL after the #, which browsers never send to a server. Your file is never involved at all: the link carries the steps, not the data. Whoever opens it runs your pipeline on their own file, in their own browser.
Does the order of the steps matter?
A great deal. Trim before dedupe, or duplicates differing only by a trailing space survive. Normalize dates before filtering on them, or you are comparing strings in different formats. Clean headers first if later steps name columns, since renaming them afterwards breaks those references. The arrows let you reorder without rebuilding, and the per-step counts show you immediately when a reorder changed the outcome.
What does switching a step off do?
It stays in the chain with its configuration intact, and is skipped. That is for testing what a step is actually contributing: switch it off, watch the counts below it change, switch it back on. Much better than deleting it and rebuilding it, and a disabled step travels in the shared link too, so you can send someone a pipeline with an optional step already set up.
Can I use SQL in a pipeline?
Yes, as a step. It runs DuckDB over whatever the previous steps produced, with the table called csv. Use it for the things the visual steps cannot express: window functions, self-joins, correlated subqueries, or just a LIMIT. It is the slowest step because of the engine download, so it is only loaded when a pipeline actually contains one.
Is the calculated column safe to run from a link someone sent me?
Yes. It is a small hand-written parser rather than eval. It understands numbers, strings, column names, a fixed set of operators and sixteen named functions, and it has no way to reach anything else in the page. Column lookups read own properties only, so an expression naming constructor or toString gets an empty cell rather than a JavaScript internal.
How big a file can a pipeline handle?
100 MB, the same as the rest of the tool pages. Everything is held in the tab, so several steps that each copy the table use more memory than one. If you are working towards something you will run on a very large file, build it against a sample first with the sampler, then swap the file in: the pipeline does not care which file it is pointed at.
Related
Build it once, send the link
Sixteen steps, live recomputation, a count under every one, and a share link that never touches a server.
Back to the builder