---
title: "CSV"
description: "How to define, write and query CSV data."
canonical_url: "https://content.nuxt.com/docs/files/csv"
---
# CSV

> How to define, write and query CSV data.

## Single-file source

When you point a collection to a single CSV file (instead of a glob), Nuxt Content **treats each data row as a separate item** in the collection.

- **Define the collection**: set `source` to the path of a single `.csv` file.
- **Item generation**: each data row becomes an item with the row’s fields at the top level (no `body` array).
- **IDs**: item IDs are suffixed with `#<rowNumber>`, where `#1` is the first data row after the header.

```ts [content.config.ts]
import { defineCollection, defineContentConfig } from '@nuxt/content'
import { z } from 'zod'

export default defineContentConfig({
  collections: {
    people: defineCollection({
      type: 'data',
      source: 'org/people.csv',
      schema: z.object({
        name: z.string(),
        email: z.string().email()
      })
    })
  }
})
```

```csv [content/org/people.csv]
name,email
Alice,alice@example.com
Bob,bob@example.com
```

Each row produces its own item. For example, the first data row will have an ID ending with `#1` and the second with `#2`. You can query by any column:

```ts
const { data: alice } = await useAsyncData('alice', () =>
  queryCollection('people')
    .where('email', '=', 'alice@example.com')
    .first()
)

const { data: allPeople } = await useAsyncData('all-people', () =>
  queryCollection('people')
    .order('name', 'ASC')
    .all()
)
```

<note>

- The header row is required and is not turned into an item.
- With a single-file source, items contain row fields at the top level (no `body`).
- If you prefer treating each CSV file as a single item containing all rows in `body`, use a glob source like `org/**.csv` instead of a single file.

</note>

## Multiple-files source

If you uses `*/**.csv` as source in configuration, Nuxt Content will treat them differently from single-file collections.<br />

**Each file(not row) will be treated as an item**, rows will be parsed into `body` field in item object as an array.

```ts [content.config.ts]
import { defineCollection, defineContentConfig } from '@nuxt/content'
import { z } from 'zod'

export default defineContentConfig({
  collections: {
    charts: defineCollection({
      type: 'data',
      source: 'charts/**.csv',
      schema: z.object({
        // Body is important in CSV files, without body field you cannot access to data array
        body: z.array(z.object({
          label: z.string(),
          value: z.number()
        }))
      })
    })
  }
})
```

Create chart files in `content/charts/` directory.

<code-group>

```csv [content/charts/chart1.csv]
label,value
A,100
B,200
C,300
```

```csv [content/charts/chart2.csv]
label,value
Foo,123
Bar,456
Baz,789
```

</code-group>

<warning>

Each CSV file should have a header row that defines the column names, which will be used as object keys when parsed.

</warning>

Now we can query charts:

```vue
<script lang="ts" setup>
// Find a single chart
const { data: chart1 } = await useAsyncData('chart1', () => {
  return queryCollection('charts')
    .where('id', '=', 'charts/charts/chart1.csv')
    .first()
})

// Get all charts
const { data: charts } = await useAsyncData('charts', () => {
  return queryCollection('charts')
    .order('id', 'ASC')
    .all()
})

</script>

<template>
  <ul>
    <li v-for="chart in charts" :key="chart.id">
      <!-- CSV data are in `chart.body` as an array -->
      <p v-for="data in chart.body">
        {{ data.label }} - {{ data.value }}
      </p>
    </li>
  </ul>
</template>
```

## Configuration

You can configure how CSV files are parsed in your `nuxt.config.ts`:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  content: {
    build: {
      csv: {
        // Convert CSV data to JSON objects
        json: true,
        // Specify custom delimiter (default is ',')
        delimiter: ','
      }
    }
  }
})
```

With `json: true` in the configuration, each row will be converted to a JavaScript object with the header row used as keys:

```json
[
  {
    "id": "1",
    "name": "John Doe",
    "email": "john@example.com"
  },
  {
    "id": "2",
    "name": "Jane Smith",
    "email": "jane@example.com"
  }
]
```

## Custom Delimiters

If your CSV files use a different delimiter, you can specify it in the configuration:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  content: {
    build: {
      csv: {
        delimiter: ';' // Use semicolon as delimiter
      }
    }
  }
})
```

This would parse CSV files like:

```csv [semicolon-data.csv]
id;name;email
1;John Doe;john@example.com
2;Jane Smith;jane@example.com
```

<note>

The CSV parser can be disabled by setting `csv: false` in the configuration if you don't need CSV support.

</note>


## Sitemap

See the full [sitemap](https://content.nuxt.com/sitemap.md) for all pages.
