Files

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.
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()
      })
    })
  }
})
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:

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()
)
  • 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. :::

Multiple-files source

If you uses */**.csv as source in configuration, Nuxt Content will treat them differently from single-file collections.
Each file(not row) will be treated as an item, rows will be parsed into body field in item object as an array.
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.
label,value
A,100
B,200
C,300
Each CSV file should have a header row that defines the column names, which will be used as object keys when parsed.
Now we can query charts:
<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:
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:
[
  {
    "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:
nuxt.config.ts
export default defineNuxtConfig({
  content: {
    build: {
      csv: {
        delimiter: ';' // Use semicolon as delimiter
      }
    }
  }
})
This would parse CSV files like:
semicolon-data.csv
id;name;email
1;John Doe;john@example.com
2;Jane Smith;jane@example.com
The CSV parser can be disabled by setting csv: false in the configuration if you don't need CSV support.