# Add data Bring data into Nexus three ways: upload files to a folder, turn a spreadsheet into a table, or use a connector for a source such as PostgreSQL or Google Sheets. This page covers the first two, and adding rows later. ## Before you start [#before-you-start] - Access to add files to the folder. Owners and admins can add anywhere. - To add rows to a table, access to change its data. A limited member needs it from an admin. See [Data access](/docs/data/data-access). - Each file has a size limit set by your plan, shown in the upload dialog. ## Files that can become a table [#files-that-can-become-a-table] Any file can be uploaded and kept. These can also become a table without any code: - CSV, TSV and plain text with a separator (`.csv`, `.tsv`, `.txt`) - JSON and JSON Lines (`.json`, `.jsonl`, `.ndjson`), and XML - Excel workbooks (`.xlsx`) - Parquet, ORC and Avro - Map data: GeoJSON, GeoParquet, GeoPackage, Shapefile (as a `.zip`), KML, KMZ, GPX and FlatGeobuf ## Upload files [#upload-files] ### Open Add data [#open-add-data] Go to and find **Add data**. ### Drop your files [#drop-your-files] Drop files on the box, or click it to choose them. ### Choose a folder [#choose-a-folder] Under **Add to**, pick one of your folders, browse all folders, or make a **New folder**. ### Upload [#upload] Select **Upload**. When the dialog says **Uploaded**, select **Open folder** to see the files. A file with the same name is saved as a new version; the earlier one is kept. If an upload stops part way, upload the same file to the same folder again: only what is missing is sent. ```python title="upload_files.py" from klarety import Nexus with Nexus.connect() as nx: folder = nx.folders.at("reports/2026") saved = folder.upload("q3-revenue.xlsx") print(saved["version"]) ``` `folders.at()` walks a path such as `reports/2026` from the folders you can reach. `upload()` waits until the version is recorded; pass `wait=False` to return once the file is accepted, which suits many uploads in a row. The command line equivalent is `klarety put q3-revenue.xlsx reports/2026`. ## Turn a spreadsheet into a table [#turn-a-spreadsheet-into-a-table] ### Start the import [#start-the-import] In , select **Turn a spreadsheet into a table**. You can also open **Nexus Lakehouse** and select **Import a table**. ### Pick the file and where to keep it [#pick-the-file-and-where-to-keep-it] Choose the file. Under **Keep the file in**, choose a folder; the file is kept there for reloading or download. ### Check the columns [#check-the-columns] Check the names and types under **Columns found**. ### Name the table [#name-the-table] Enter a **Table name**. If the name is taken, you see **This table already exists** and choose **Add rows** or **Replace rows**. ### Import [#import] Select **Import**. When it finishes, select **Open table**. A file already in Object Storage becomes a table the same way: open its menu and choose **Make a table**. Preview first, so a wrong column guess is caught before any row is written. Then load: ```python title="import_table.py" import time from klarety import Nexus with Nexus.connect() as nx: preview = nx.ingest_preview("customers.csv", into="customers") print(preview) run = nx.ingest("customers.csv", into="customers", schema="default") while run.state in ("accepted", "running"): time.sleep(2) run = nx.ingest_status(run.run_id) print(run.state) ``` A run ends as `succeeded`, `failed` or `cancelled`. `ingest()` takes a local path, which it uploads first, or a URI. From the command line: `klarety ingest customers.csv --into customers`. ## Add rows to a table that already exists [#add-rows-to-a-table-that-already-exists] When a table already exists, choose how the new rows land: | Option in the app | `mode` in code | What happens | | --- | --- | --- | | **Add rows** | `auto` | New rows are added. Rows already in the table are not added twice. | | **Update rows by key** | `upsert` | You choose the columns that identify a row. A row whose key matches is replaced; the rest are added. | | **Replace all rows** | `replace` | The table holds only this file afterwards. History keeps the old rows. | The table keeps only the new file. The old rows stay in [history](/docs/data/undo-and-restore), so you can go back if the file was wrong. **Add rows** suits new records, such as this month's orders. **Update rows by key** suits corrected records, such as a fresh customer export keyed by `customer_id`. **Replace all rows** suits a file that is the full, current truth. ### Open the table [#open-the-table] In **Nexus Lakehouse**, open the table and select **Add data from a file**. ### Choose the file [#choose-the-file] Pick the file and the folder to keep it in. ### Choose how the rows land [#choose-how-the-rows-land] Under **How the rows land**, choose **Add rows**, **Update rows by key** or **Replace all rows**. For **Update rows by key**, tick the **Columns that identify a row**. ### Load [#load] Select **Load**. You can close the dialog; the load keeps going, and the **History** tab shows the new version when done. ```python title="update_by_key.py" from klarety import Nexus with Nexus.connect() as nx: run = nx.ingest( "customers-latest.csv", into="customers", mode="upsert", key=["customer_id"], ) print(run.run_id, run.state) ``` A key has at most 8 columns. One file loads into one table once: loading the same file again does nothing unless you pass `force=True`. To load rows from a connected source, name the connection and a query: `nx.ingest(connection="CONNECTION_ID", query="SELECT * FROM orders", into="orders")`. ## Rows that fail a data check [#rows-that-fail-a-data-check] Rows that break a table's data check are set aside; the rest load as normal. The check panel shows how many rows each load wrote and set aside. See [Work with tables](/docs/data/tables#add-data-checks). ## What can go wrong [#what-can-go-wrong] Split the file, or keep it as a file and load it from code in parts. Open the table's **Columns** tab to check what was read. From code, run `nx.ingest_preview()` first: it shows what would happen before any row is written. The message after **Not loaded** names the reason, often a key column missing from the file under **Update rows by key**. **Add rows** never adds a row twice, and the same file is not loaded into the same table twice. If you meant to load it again, choose **Replace all rows**, or pass `force=True` in code. ## Where to go next [#where-to-go-next] - [Work with tables](/docs/data/tables): browse, edit and check the table you just made. - [Object storage](/docs/data/object-storage): import new files from a folder automatically. - [Connectors](/docs/connectors): bring data in from PostgreSQL, Google Sheets, Amazon S3 and more. - [Query with SQL](/docs/data/sql-editor): ask questions of your new table.