Import CSV data straight into your Hasura API.
Your users upload a spreadsheet. CSVbox maps their columns to the Postgres tables Hasura tracks, validates every row, and writes clean data directly. The rows are queryable through your GraphQL API the moment they land — no ETL job, no custom mutation script.
- Validated data only
- Column mapping included
- SOC 2 Type II + GDPR
Hasura generates a GraphQL API over your Postgres database instantly — every table you track becomes queries, mutations, and subscriptions with row-level permissions attached. What Hasura does not give you is a way for end users to get bulk data in. Pushing a few thousand spreadsheet rows through a GraphQL mutation means building an upload UI, a parser, a validator, and a batching layer yourself.
CSVbox handles that entire front half. Point a PostgreSQL destination at the same database Hasura is connected to, and CSVbox parses the upload, maps the user’s headers to your columns, coerces types, validates every row, and inserts the clean ones. Because Hasura reads from those same tables, imported rows show up in your GraphQL API — and in any active subscription — immediately, with your existing permission rules applied on read.
- Writing at the Postgres layer keeps large imports fast — no per-row GraphQL round trip and no mutation payload size limits to work around.
- If you would rather keep writes behind the API, expose a RESTified endpoint or a Hasura Action for your insert mutation and use the CSVbox API / Webhook destination instead.
- Hasura tracks the table, not the writer: rows inserted by CSVbox fire the same event triggers and appear in live subscriptions, exactly like rows written through a mutation.
How It Works
- 1Connect the database behind Hasura
In the CSVbox dashboard, add a PostgreSQL destination. Use the same connection details Hasura uses — on Hasura Cloud, find them under Project → Data → your database source. CSVbox connects over TLS and stores credentials encrypted.
- 2Map to a tracked table
Select the target table — any table Hasura already tracks. CSVbox reads its column definitions so you can map each schema field to a column, or let CSVbox auto-match by name.
- 3Choose insert or upsert
Select Insert (append all rows) or Upsert (insert or update on a unique column such as email or an external ID). Upsert uses Postgres ON CONFLICT — the same mechanism behind Hasura’s on_conflict mutation argument.
- 4Embed the importer
Drop the CSVbox widget into your app. When a user uploads a file, CSVbox validates it and writes passing rows to the table. Query them through Hasura right away — failed rows stay in the importer for the user to correct.
Querying Imported Rows
# Rows written by CSVbox are available through your
# existing Hasura API - no schema or metadata changes.
query ImportedContacts {
contacts(order_by: { created_at: desc }, limit: 20) {
id
email
first_name
company
created_at
}
}
# And in live subscriptions, as they arrive:
subscription NewContacts {
contacts(order_by: { created_at: desc }, limit: 1) {
id
email
}
}Configuration Options
| Option | Description |
|---|---|
| Connection | Host, port, database, user, password of the source Hasura tracks (TLS enforced) |
| Target table | Any table in the connected database; tracked tables appear in GraphQL immediately |
| Write mode | Insert (append) or Upsert (insert/update on conflict) |
| Unique column | Column used for upsert conflict resolution |
| Column mapping | Map schema fields to table columns; rename or skip |
| Null handling | Empty cells → NULL or a default value |
| Alternative path | API / Webhook destination pointed at a Hasura RESTified endpoint or Action |
Common Use Cases
New customers upload their existing contacts, products, or accounts at signup. The records land in Postgres and are served by your Hasura API before the user leaves the onboarding screen.
Import per-tenant data into tables guarded by Hasura row-level permissions. The tenant column is mapped like any other field, so imported rows respect the same access rules on read.
Accept a customer’s export from a previous tool as CSV or Excel and write it straight into your tracked schema, without hand-writing a bulk mutation for every table.
Let internal teams upload pricing tables, catalogs, or reference data on a schedule. Event triggers on the table fire as usual, so downstream workflows keep running.
Frequently Asked Questions
Does CSVbox write through the GraphQL API or directly to Postgres?
The recommended path writes directly to the Postgres database Hasura is connected to, using the PostgreSQL destination. It avoids per-row GraphQL round trips and handles large files efficiently. If you need writes to go through the API layer instead, use the API / Webhook destination pointed at a Hasura RESTified endpoint or Action.
Do imported rows appear in my GraphQL API automatically?
Yes, as long as the table is tracked in Hasura. Hasura serves whatever is in the table, so rows inserted by CSVbox are queryable immediately — no metadata reload and no schema change required.
Will Hasura event triggers and subscriptions fire on imported rows?
Yes. Event triggers are Postgres triggers created by Hasura, so they fire on inserts regardless of where the write came from. Live subscriptions pick up imported rows the same way they pick up rows written by a mutation.
How do Hasura permissions apply to imported data?
Hasura permissions govern access through the GraphQL API, not writes made directly at the database level. CSVbox inserts using the database credentials you configure, and Hasura applies your existing row and column permissions when clients read the data. Map your tenant or owner column in the importer so rows land with the right scope.
Does this work with Hasura Cloud and self-hosted Hasura?
Yes. The integration depends on the Postgres source, not the Hasura edition or hosting model. Point CSVbox at the same connection string your Hasura project uses — for a Neon-backed Hasura Cloud project, use the pooled connection string.
What happens when a row fails validation?
Failed rows surface in the importer UI for the user to fix inline. They never reach your database, so your GraphQL API is never exposed to partial or malformed records. Passing rows are inserted; failing rows are held for correction.