Skip to content

Guides

Build a dashboard from a file

Upload a CSV or Excel file through your AI tool, author against the catalog it produces, and publish a dashboard that reads that one file.

Not every set of numbers lives in a warehouse. If yours is a CSV or an .xlsx workbook on your disk, you can hand that file to Dashies once and build a dashboard on it, with the same spec, the same tiles and the same versioning as a warehouse dashboard.

The file goes from your disk straight to Dashies. It is not read into your conversation with your AI tool, and it is not pasted into a spec.

Before you start

You needWhy
A paid plan or a trial on the workspaceUploading is gated the same way connecting a warehouse is. See Plans and what is gated.
A creator seatA viewer seat may read the workspace's dashboards and may not add data to it.
A free connection slot, for the first upload onlyA workspace's uploads share one data connection, created by the first upload and spending one of the workspace's slots. Later uploads reuse it and need no slot. See Connections and scope.
An AI client that can run a shell commandThe bytes are sent by a curl line your AI tool runs.

A client with no shell cannot upload

The upload is a one-time URL plus a curl command, run by the agent in its own shell. That is what keeps the file out of the conversation, and it is also the one requirement that cannot be worked around today: an AI client with no shell cannot take this path at all.

There is no upload form in the Dashies web app, on any plan. The app has no authoring surface of any kind; a dashboard, and now a file, arrives through your AI tool.

What happens to the file

  1. Your AI calls create_file_upload.

    It passes the filename and, worth doing, the exact byte size. Nothing is sent yet. The answer is a one-time URL and the exact curl command to run. The ticket in it works once and expires; the response prints the exact time.

  2. Your AI runs the command it was given.

    The file is PUT to Dashies. Only a few uploads may be in progress in one workspace at a time; if you are over that, the refusal names the number.

  3. Dashies converts the file, once.

    A CSV becomes one table. A workbook becomes one table per visible worksheet that has rows: hidden sheets, chart sheets and empty ones are skipped, each with a warning in the catalog saying which and why. Name a hidden sheet in the sheets override to read it anyway.

    Each column's type is decided by reading the whole file rather than a sample, and the verdict is written down as a catalog.

  4. Your AI polls get_file_upload until the status is ready or failed.

    A ready answer carries the catalog: every table, every column, its declared type, and the findings that kept a column as text. It also carries the SHA-256 of the bytes Dashies stored, which you can compare against shasum -a 256 on your own copy.

  5. Your AI authors against the upload.

    introspect_schema, explore_data and validate_cube_sql all take the uploaded-file connection as connection and the upload id as upload.

  6. Your AI publishes.

    The spec's source.connection is the uploaded-file connection and source.upload is the upload id. See Source.

What the SQL looks like

The statement returns records, not a summary

Your statement returns one row per underlying record, carrying the columns each number is worked out from, and each number is declared in the spec rather than worked out in the SQL. Dashies holds those rows and works the numbers out when a reader opens the page, so a statement that has already aggregated gets aggregated a second time.

Nothing refuses the wrong shape. A plain total survives the wrong grain, so a statement that groups reads as correct until somebody adds a count, and then the count is the number of groups you made rather than the number of records.

This is the held shape, the one a statement takes against a warehouse connection or the workspace's uploaded-file source, and an uploaded file is always on that side. So the four in-file modes on Datasets and the four modes are not a choice here, and a publish that asks for one is refused. Designing the cube has the shape's rules in full, and A warehouse dashboard is served states it on the warehouse side.

Your SQL runs against the tables the conversion made, so two things differ from every page under Connect a warehouse. Neither of them is the shape.

The table name comes from the file, not from you. A CSV's table is named after the filename without its extension, folded down to a-z0-9_: Q3 Sales.csv is queried as q3_sales. A workbook's tables are named from the sheet names the same way, and because two sheet names can fold to one table name, a collision gets a numeric suffix.

The folding has more rules than are worth carrying in your head: accents fold to the base letter rather than to _, runs of punctuation collapse to a single _, a name starting with a digit gains a t_ prefix, and a long one is truncated. So the catalog is the authority - read the table name out of get_file_upload rather than deriving it here.

Column names are kept exactly as the header spelled them, spaces and capitals included, so quote them and alias to the key grammar the spec wants:

select
  "Order Date"   as order_date,
  "Region"       as region,
  "Net Amount"   as net_amount
from q3_sales

That statement has no GROUP BY and no aggregate, and that is the record grain the shape asks for rather than a simplification made for the example. net_amount arrives as the column it is on each record, and the spec is where you say to total it.

Four things about a header row are refused at conversion, each with a sentence naming the column's position: a blank header, an over-long one, a duplicate, and two headers that differ only in capitals. That last one is the exception to headers being kept verbatim: your capitals are preserved, but Region and region in one file cannot be told apart once quoted, so the file is refused rather than guessed at.

Changing the data means a new upload

An upload is immutable, and nothing replaces a file in place. There is no "update this file" call, and re-running the curl command against a spent ticket does not work.

To publish newer numbers: create a new upload, send the new file, and republish the spec with the new id in source.upload.

Dashies never picks the newest upload for you

source.upload is required on a file source and a publish without it is refused. That is deliberate: if the newest upload won by default, republishing a byte-identical spec would move the numbers on the page with nothing in the document saying why, and no diff anywhere would show it. Naming the upload makes a data change a document change.

If you are arriving from Tableau, this is the rule its own web upload works by as well: a file uploaded by hand is not refreshed for you, and new data means uploading a new version of the file.

A schedule does not fetch a new file

A cadence other than manual is accepted on a file source, with a warning, rather than refused. It is worth knowing exactly what it does: a scheduled refresh re-runs your SQL over the same converted file. That only changes the numbers if the SQL is time-relative, such as a trailing window or anything reading current_date. It cannot pick up a new file.

schedule: manual is the honest default here.

Getting the read wrong, and fixing it without re-uploading

If the conversion typed a column in a way you did not want, or read the CSV with the wrong delimiter, encoding or header row, you do not upload the file again. Pass reconvert_of with the original upload id and an overrides object to create_file_upload: the same stored bytes are read again under the new instructions, and the original upload is left untouched.

Each override is checked against a census of the same stored bytes read under your new instructions, so an override the data does not support fails that upload and names your value instead of silently dropping rows.

The window for this is bounded. A failed upload's stored bytes are kept for a while and then dropped, and re-converting works only while they are there; after that you upload the file again. Reading a failed upload's status does not extend that window.

What is refused

RefusedWhat you get
A legacy .xls workbook, or a password-protected workbookthe file is a legacy .xls workbook or a password-protected workbook. Save it as .xlsx without a password.
Another Office file, such as .docx or .xlsba sentence saying it is not an .xlsx, and to save it as one
A file that is not a spreadsheet at all, such as a PDF or an imagenot a sentence about the format. See the note below.
A file over the size caprefused before anything is sent when the upload declares its size, and at the PUT otherwise. See Limits.
A workspace with no paid plan or trialA paid plan is required to upload a file. Uploaded files are available on paid plans and during a trial.
A viewer seatYou hold a view-only role in this workspace, so you cannot upload files to it. A workspace admin can change your role.
A workspace with no connection slot lefta sentence naming the data-connection limit

A failed upload is not the end of it, and the sentence beside the failure token decides what to do. Where it names an override, re-convert the same stored bytes with overrides. Where the file itself is wrong, fix it and create a new upload.

Sending the wrong file does not get you a sentence about formats

Dashies decides what a file is from its first bytes, never from its name or its content type. Only two shapes are recognised: a zip, which is where an .xlsx lives, and a legacy Office container. Anything else is attempted as text.

So a PDF or an image is not refused as a PDF or an image. It is read as text, fails on the first byte that text cannot contain, and comes back saying the file is not valid UTF-8 or carries a NUL byte, usually suggesting an encoding override. That advice is right for a mis-encoded CSV and useless for a PDF, so read the filename you sent before you reach for an override.

A file that genuinely is text but is not tabular, such as JSON or a log, is not refused at all for being the wrong kind of thing. It either fails on columns or rows, or converts into a table that is real and meaningless. Check the catalog get_file_upload returns before you build on it.

The size cap is smaller than a file-import BI tool's, deliberately

FILE_UPLOAD_MAX_BYTES on Limits is the whole of it: there is no multipart upload and no chunking, so a file over the cap cannot be sent in pieces. Splitting the data across several files works, and each one is its own upload.

Dashies does not claim parity here with a BI tool whose headline feature is importing a large file. Data past this cap belongs in a warehouse connection, which has no source-file ceiling at all.

How long an upload is kept

Ordinarily a reference keeps an upload alive. A converted upload that a live dashboard reads, or that a retained version names, is not collected while that reference exists. One that nothing references is removed after a grace period during which nothing has referenced or used it, so the copies left behind by iterating on a file do not accumulate forever.

That is why the version-retention rules matter here in a way they do not for a warehouse dashboard: pruning an old version can be what releases the last reference to an old upload. See Version history.

A failed upload is outside that rule: it is dropped on a shorter clock of its own whether or not anything names it. That costs you nothing, because a failed upload cannot be published in the first place.

Deleting the connection deletes the files, references and all

On every other data source, deleting the connection withdraws a credential and the dashboards built on it keep their numbers. Here the connection is the data. Deleting the workspace's Uploaded files connection moves every upload under it to deleted, the ones live dashboards are reading included, and nothing refuses or warns first.

The web app cannot do this, because the uploaded-file connection is not on the Data sources page and there is nothing there to press. What can do it is a tool call or a script naming the connection id, which is the same id list_connections reports beside your uploads. Treat that id as the workspace's spreadsheet data rather than as a connection you can drop and re-add.

There is no undo. Recovering means uploading each file again and republishing every dashboard that read it against the new upload.

A workspace whose plan has ended has its uploaded files removed along with the rest of its stored data. That one is not silent: you are told before anything goes and the notice names the date. See Plans and what is gated.

Check it worked

Ask your AI tool for the workspace's connections. The uploaded-file row is labelled Uploaded files, and it is the only row that carries an uploads block: your recent uploads, each with its id, filename and status.

Ask your AI rather than the web app, because the app does not show this connection at all. It is hidden from the Data sources page, which lists the connections you create there. That is the app being consistent about having no upload surface rather than anything being wrong; see Connections and scope.

Then open the published dashboard and compare one tile against the same figure in the spreadsheet.

Next

Author a dashboard for the rest of the authoring loop, or Connections and scope for how the uploaded-file connection sits beside your warehouse ones.