Back to all posts

A Different Way to Think About CSV Import

I started building Updog because I could not find the data import product I wanted to use.

The limits felt artificial. The UX was not good enough. The privacy story was heavier than it needed to be. The pricing became another thing to think about. And after all of that, the import flow still often felt like a small upload widget trying to handle a serious product moment.

CSV import looks simple only from far away. In a real product, the file almost never matches the system. Column names are different. Dates are formatted differently. Required fields are missing. Some values are valid for the user, but not valid for the product. Some rows can be fixed automatically. Some rows need attention.

That was the part that bothered me. The user is trying to bring external data into the product, but the workflow around that moment often becomes heavier than the moment itself. It turns into backend work, privacy questions, pricing rules, and UI compromises before the product has even helped the user prepare the file.

I wanted to try a different shape for that workflow.

The browser became the product idea

The core idea was to make the import step happen in the browser.

Updog is client-side code. When a user uploads a file, the SDK works with that file locally in the browser: parsing it, mapping columns, checking values, and preparing the final structured data for the host application. The raw file data does not get sent to Updog servers, because Updog does not need a server to run the import flow.

The host application still decides what happens after submission. Updog handles the preparation step inside the browser. The file is processed by the SDK locally. It never reaches Updog's servers.

That was the foundation I wanted.

Real files need an honest benchmark

A browser-first importer still needs to be honest about browser limits. A browser tab has memory constraints, and large files are expensive. The data needs to live somewhere. So do validation states, edits, filters, selections, and the rest of the working state required to make the import usable.

That is why one million rows became an important benchmark for Updog. The point was not that someone will manually inspect one million rows. Nobody should do that. The point is that real customer files can be large, and the product should have enough headroom to handle them without immediately turning import into a server-side project.

One million rows is a practical ceiling, not an unlimited claim. It says that the browser can go surprisingly far when the product is built around its strengths, but the limit is still real. If the import experience works at that scale, then 50,000 or 100,000 rows should feel normal instead of dangerous.

How it works without rendering one million rows

Updog does not render one million HTML rows. That would be the wrong model.

A normal DOM table is useful for normal tables, but it is not the right foundation for a large import experience. When the dataset grows, the interface starts to pay for every wrong rendering decision. Scrolling becomes uneven, rows appear late, and the product begins to feel like it is barely holding together.

Updog uses a canvas-based grid. It draws what the user can see, instead of asking the browser to manage the whole dataset as page elements. Heavier operations, like filtering, can run in a Web Worker, so the main interface can stay responsive while the data is being processed. The browser still holds the data in memory, and that cost is real. The difference is that the UI is built around the browser's strengths instead of fighting them.

The goal is not to make a human scroll through a million rows. The goal is to make the product capable of working with a large file, then give the user tools to narrow the problem. Exact filters, validation states, error views, search, column transforms, and bulk actions are what make large imports manageable. The user should not be fixing every broken value by hand. Most issues should be handled automatically, and the editor exists for the remaining cases where the data still needs human correction.

What Updog handles

Updog is a browser-first JavaScript SDK for importing CSV and other structured files into web apps. It handles the preparation step: mapping columns, checking values, showing issues, narrowing the data that needs attention, and returning structured data back to the host application.

The application stays in control of what happens after submission. It can save the data, call an API, run business logic, or start a backend process. Some data workflows naturally belong there: scheduled jobs, recurring pipelines, warehouse-scale imports, very large migrations, and automated infrastructure flows.

Updog is focused on the user-facing import step inside a web application. The moment when someone brings a file into a product, the product helps prepare it, and clean structured data is submitted into the system. The browser can do a lot when the workflow fits the browser, and Updog is built for that specific workflow.

Pricing should feel predictable

Client-side architecture also made one pricing question easy to answer: if the import work happens in the customer's browser, every import, row, or feature should not become a pricing event. That kind of pricing changes how teams think about usage and makes a normal product workflow feel metered.

Updog is priced per production domain. Development and localhost are free. Subdomains are included. All features are included. There are no per-import fees, no row fees, no usage tiers, and no Updog branding.

The version I wanted to exist

I wanted CSV import to feel more secure, more usable, more predictable, and less artificially constrained.

That became Updog: a browser-first CSV import SDK where raw files can stay in the browser during preparation, real files have enough headroom to feel safe, users get tools to narrow and fix the data that needs attention, and pricing does not punish usage.

It is a simple idea, but it changes the shape of the product. CSV import does not need to become a heavy infrastructure problem every time a user brings data into a web app. That is the product I wanted to use, so that is the product I started building.