---
title: "Auto-Generate Columns"
framework: vue
version: "36.1.0"
---

# Auto-Generate Columns

Column definitions can be generated automatically from `rowData`, without defining them upfront. This is useful when working with dynamic or unknown data shapes.

Set `autoGenerateColumnDefs` to `true` and the grid scans `rowData` for the first non-null row, then creates a column for each of its keys:

#### Auto-Generate Columns

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
  AutoGenerateColumnDefsOptions,
  AutoGenerateColumnsModule,
  ClientSideRowModelModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  AutoGenerateColumnsModule,
]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :autoGenerateColumnDefs="true"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const rowData = ref<any[] | null>([
      {
        name: "Alice",
        address: { city: "London", country: "UK" },
        scores: { maths: 92, science: 88 },
      },
      {
        name: "Bob",
        address: { city: "Paris", country: "France" },
        scores: { maths: 75, science: 91 },
      },
      {
        name: "Charlie",
        address: { city: "Berlin", country: "Germany" },
        scores: { maths: 84, science: 79 },
      },
      {
        name: "Diana",
        address: { city: "Madrid", country: "Spain" },
        scores: { maths: 96, science: 85 },
      },
      {
        name: "Eve",
        address: { city: "Rome", country: "Italy" },
        scores: { maths: 68, science: 94 },
      },
    ]);

    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;
    };

    return {
      gridApi,
      rowData,
      onGridReady,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Auto-Generate Columns](https://www.ag-grid.com/examples/auto-generate-columns/nested-objects/vue3)

```js
const gridOptions = {
    autoGenerateColumnDefs: true,
    rowData: myData,
};
```

## Column Generation

The grid scans `rowData` for the first non-null row and creates columns based on value types:

- **Primitive values** (strings, numbers, booleans, bigints, Date instances) — a leaf column.
- **Plain objects** — a column group by default, with nested keys recursed into. The `headerName` is derived from the key name.
- **Arrays** — a leaf column if the first element is a primitive value; skipped if the array is empty or contains objects. Arrays render as a comma-separated string.
- **null/undefined values** — a leaf column by default.
- **Functions** — skipped.

For example, given this row data:

```js
rowData: [
    { user: { name: 'Alice', age: 30 }, score: 100 },
]
```

The generated column definitions are:

```js
columnDefs: [
    {
        headerName: 'User',
        children: [
            { field: 'user.name', headerName: 'Name' },
            { field: 'user.age', headerName: 'Age' },
        ],
    },
    { field: 'score' },
]
```

> **Note**
>
> Row data keys containing dots (e.g. `"user.name"`) are treated as nested paths by default. Set `suppressFieldDotNotation` to `true` to treat dotted keys as literal field names. See [Accessing Row Data Values](https://www.ag-grid.com/vue-data-grid/value-getters/#field) for details.

Column groups are only produced when the value for a key in the first scanned row is a non-empty plain object, with the default `objectValues: 'group'`. Arrays, primitives, dates, class instances and empty objects all yield leaf columns or are skipped. Ensure `rowData` has the nested structure you expect before relying on generated group headers.

## Configuration

Pass an `AutoGenerateColumnDefsOptions` object instead of `true` to control how each value type is handled. The example below lets you toggle each option to see how it affects the generated columns:

#### Configuration

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  AutoGenerateColumnDefsOptions,
  AutoGenerateColumnsModule,
  ClientSideRowModelModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  AutoGenerateColumnsModule,
]);

const config: AutoGenerateColumnDefsOptions = {
  objectValues: "group",
  arrayValues: "primitives",
  nullishValues: "include",
};

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="example-wrapper">
      <div class="example-header">
        <label>
          objectValues:
          <select id="objectValues" v-on:change="onObjectValues()">
            <option value="group">group</option>
            <option value="flatten">flatten</option>
            <option value="skip">skip</option>
          </select>
        </label>
        <label>
          arrayValues:
          <select id="arrayValues" v-on:change="onArrayValues()">
            <option value="primitives">primitives</option>
            <option value="include">include</option>
            <option value="skip">skip</option>
          </select>
        </label>
        <label>
          nullishValues:
          <select id="nullishValues" v-on:change="onNullishValues()">
            <option value="include">include</option>
            <option value="skip">skip</option>
          </select>
        </label>
      </div>
      <ag-grid-vue
        style="width: 100%; height: 100%;"
        @grid-ready="onGridReady"
        :rowData="rowData"
        :autoGenerateColumnDefs="autoGenerateColumnDefs"></ag-grid-vue>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const rowData = ref<any[] | null>([
      {
        name: "Alice",
        age: 32,
        address: { city: "London", country: "UK" },
        roles: ["admin", "user"],
        notes: null,
      },
      {
        name: "Bob",
        age: 28,
        address: { city: "Paris", country: "France" },
        roles: ["user"],
        notes: null,
      },
      {
        name: "Charlie",
        age: 35,
        address: { city: "Berlin", country: "Germany" },
        roles: ["admin"],
        notes: null,
      },
      {
        name: "Diana",
        age: 24,
        address: { city: "Madrid", country: "Spain" },
        roles: ["user", "moderator"],
        notes: null,
      },
      {
        name: "Eve",
        age: 29,
        address: { city: "Rome", country: "Italy" },
        roles: ["admin", "moderator"],
        notes: null,
      },
    ]);
    const autoGenerateColumnDefs = ref<boolean | AutoGenerateColumnDefsOptions>(
      { ...config },
    );

    const onObjectValues: () => void = () => {
      const value = (
        document.getElementById("objectValues") as HTMLSelectElement
      ).value;
      config.objectValues =
        value as AutoGenerateColumnDefsOptions["objectValues"];
      gridApi.value.setGridOption("autoGenerateColumnDefs", { ...config });
    };
    const onArrayValues: () => void = () => {
      const value = (
        document.getElementById("arrayValues") as HTMLSelectElement
      ).value;
      config.arrayValues =
        value as AutoGenerateColumnDefsOptions["arrayValues"];
      gridApi.value.setGridOption("autoGenerateColumnDefs", { ...config });
    };
    const onNullishValues: () => void = () => {
      const value = (
        document.getElementById("nullishValues") as HTMLSelectElement
      ).value;
      config.nullishValues =
        value as AutoGenerateColumnDefsOptions["nullishValues"];
      gridApi.value.setGridOption("autoGenerateColumnDefs", { ...config });
    };
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;
    };

    return {
      gridApi,
      rowData,
      autoGenerateColumnDefs,
      onGridReady,
      onObjectValues,
      onArrayValues,
      onNullishValues,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Configuration](https://www.ag-grid.com/examples/auto-generate-columns/configuration/vue3)

Properties available on the `AutoGenerateColumnDefsOptions` interface.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `objectValues` | `'group' \| 'flatten' \| 'skip'` |  | `'group'` | How to handle plain-object values. `'group'` recurses into the object and creates a column group, `'flatten'` recurses and creates flat leaf columns using dotted field paths, `'skip'` ignores the field entirely. |
| `arrayValues` | `'primitives' \| 'include' \| 'skip'` |  | `'primitives'` | How to handle array values. `'primitives'` creates a leaf column only when the first element is a primitive value, `'include'` creates a leaf column for all arrays, `'skip'` ignores them. |
| `nullishValues` | `'include' \| 'skip'` |  | `'include'` | How to handle `null` and `undefined` values. `'include'` creates a leaf column, `'skip'` ignores them. |

Setting `objectValues` to `'flatten'` produces top-level columns with dotted field paths instead of nested groups:

```js
// Row data: { name: 'Alice', address: { city: 'London' } }
// With objectValues: 'flatten':
columnDefs: [
    { field: 'name' },
    { field: 'address.city', headerName: 'City' },
]
```

## Updating Row Data

Columns are regenerated each time `rowData` is set. Only the keys from the first non-null row are used, so columns update when the data shape changes.

By default, column order matches the key order of that first row. Set `maintainColumnOrder` to `true` to preserve existing column positions when the data shape changes:

```js
const gridOptions = {
    autoGenerateColumnDefs: true,
    maintainColumnOrder: true,
};
```

See [Maintain Column Order](https://www.ag-grid.com/vue-data-grid/column-updating-definitions/#maintain-column-order) for details.

Setting `rowData` to `[]` clears both the rows and the column definitions.

> **Note**
>
> Updating data via transactions (`applyTransaction` / `applyTransactionAsync`) does not trigger column generation.

## Customising Generated Columns

[Default Column Definitions](https://www.ag-grid.com/vue-data-grid/column-definitions/#default-column-definitions) apply to auto-generated columns the same way as manually defined ones. This is the simplest way to set common properties like filtering or resizing.

For per-column customisation, use the `processAutoGeneratedColumnDefs` callback to modify, reorder, or replace columns before they are applied. The callback receives `params.columnDefs` (which may include `ColGroupDef` entries when row data contains nested objects) and `params.rowData`, and returns the final `(ColDef | ColGroupDef)[]`.

Use `forEachColDef` to mutate leaf column properties without having to handle group recursion yourself:

```js
import { forEachColDef } from 'ag-grid-community';

const gridOptions = {
    autoGenerateColumnDefs: true,
    rowData: myData,
    processAutoGeneratedColumnDefs: ({ columnDefs }) => {
        forEachColDef(columnDefs, (colDef) => {
            colDef.hide = colDef.field === 'internalId';
        });
        // Add a custom column
        columnDefs.push({ headerName: 'Actions', cellRenderer: ActionsRenderer });
        return columnDefs;
    },
};
```

The example below uses [Column Types](https://www.ag-grid.com/vue-data-grid/column-definitions/#column-types) to apply a `currencyColumn` type to any column whose field contains `"profit"`:

#### Customising Columns

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
  AutoGenerateColumnDefsOptions,
  AutoGenerateColumnsModule,
  ClientSideRowModelModule,
  ColDef,
  ColTypeDefs,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  ProcessAutoGeneratedColumnDefs,
  enableDevValidations,
  forEachColDef,
} from "ag-grid-community";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  AutoGenerateColumnsModule,
  NumberFilterModule,
]);

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <ag-grid-vue
      style="width: 100%; height: 100%;"
      @grid-ready="onGridReady"
      :processAutoGeneratedColumnDefs="processAutoGeneratedColumnDefs"
      :autoGenerateColumnDefs="true"
      :columnTypes="columnTypes"
      :defaultColDef="defaultColDef"
      :rowData="rowData"></ag-grid-vue>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const processAutoGeneratedColumnDefs = ref<ProcessAutoGeneratedColumnDefs>(
      (params) => {
        forEachColDef(params.columnDefs, (colDef) => {
          if (colDef.field?.includes("profit")) {
            colDef.type = "currencyColumn";
          }
        });
        return params.columnDefs;
      },
    );
    const columnTypes = ref<ColTypeDefs>({
      currencyColumn: {
        valueFormatter: (params) =>
          params.value == null ? "" : "£" + params.value.toLocaleString(),
        filter: "agNumberColumnFilter",
      },
    });
    const defaultColDef = ref<ColDef>({
      flex: 1,
    });
    const rowData = ref<any[] | null>([
      {
        product: "Widget A",
        region: "North",
        profit: 12500,
        profitMargin: 0.15,
      },
      {
        product: "Widget B",
        region: "South",
        profit: 8300,
        profitMargin: 0.11,
      },
      {
        product: "Gadget X",
        region: "East",
        profit: 21000,
        profitMargin: 0.22,
      },
      { product: "Gadget Y", region: "West", profit: 5600, profitMargin: 0.08 },
      {
        product: "Gizmo Z",
        region: "North",
        profit: 17400,
        profitMargin: 0.19,
      },
    ]);

    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;
    };

    return {
      gridApi,
      processAutoGeneratedColumnDefs,
      columnTypes,
      defaultColDef,
      rowData,
      onGridReady,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Customising Columns](https://www.ag-grid.com/examples/auto-generate-columns/customising-columns/vue3)

## File Drop Overlay

When `autoGenerateColumnDefs` is enabled and no `rowData` is present, a file drop overlay is shown automatically when `processFileInput` is provided. Files can be dragged onto the overlay or selected via a browse button. See [Overlays](https://www.ag-grid.com/vue-data-grid/overlays-overview/) for more on grid overlays.

Provide a `processFileInput` callback. The `params` object contains the selected `files` array along with `success` and `fail` callbacks. Call `success(rowData)` to load the parsed data into the grid, or `fail(message)` to display an error in the overlay using the `fileInputProcessingFailed` locale.

`params.files` contains every file the user dropped or selected. The example below processes the first file only; iterate over `params.files` to handle multiple files.

```js
const gridOptions = {
    autoGenerateColumnDefs: true,
    processFileInput: (params) => {
        const file = params.files[0];
        const reader = new FileReader();
        reader.onload = (e) => {
            try {
                const rowData = parseCsv(e.target.result);
                params.success(rowData);
            } catch {
                params.fail('Failed to parse file');
            }
        };
        reader.readAsText(file);
    },
};
```

The example below auto-generates columns from various data sources. Files can be dragged onto the overlay, selected via the browse button, or loaded from the sample data dropdown. The toolbar **Upload File** button re-shows the overlay by setting `activeOverlay` to `'agFileInputOverlay'`.

#### Auto-Generate Columns

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
import {
  AutoGenerateColumnDefsOptions,
  AutoGenerateColumnsModule,
  ClientSideRowModelModule,
  ColDef,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  NumberFilterModule,
  ProcessFileInputParams,
  TextFilterModule,
  Toolbar,
  ToolbarItemActionParams,
  enableDevValidations,
} from "ag-grid-community";
import { ToolbarModule } from "ag-grid-enterprise";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

ModuleRegistry.registerModules([
  ClientSideRowModelModule,
  AutoGenerateColumnsModule,
  TextFilterModule,
  NumberFilterModule,
  ToolbarModule,
]);

declare let XLSX: any;

function parseWorkbook(workbook: any): Record<string, unknown>[] {
  const firstSheetName = workbook.SheetNames[0];
  const worksheet = workbook.Sheets[firstSheetName];
  return XLSX.utils.sheet_to_json(worksheet);
}

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div class="example-wrapper">
      <div class="example-header">
        <label>
          Sample data:
          <select id="sampleData" v-on:change="onLoadSampleData()">
            <option value="">-- Select --</option>
            <option value="small-row-data.json">Cars (JSON)</option>
            <option value="small-olympic-winners.json">Olympic Winners (JSON)</option>
            <option value="weather-se-england.json">Weather (JSON)</option>
            <option value="stocks.json">Stocks (JSON)</option>
            <option value="olympic-data.xlsx">Olympic Data (Excel)</option>
          </select>
        </label>
      </div>
      <ag-grid-vue
        style="width: 100%; height: 100%;"
        @grid-ready="onGridReady"
        :processFileInput="processFileInput"
        :autoGenerateColumnDefs="true"
        :defaultColDef="defaultColDef"
        :toolbar="toolbar"
        :rowData="rowData"></ag-grid-vue>
      </div>
        </div>
    `,
  components: {
    "ag-grid-vue": AgGridVue,
  },
  setup(props) {
    const gridApi = shallowRef<GridApi | null>(null);
    const defaultColDef = ref<ColDef>({
      minWidth: 80,
      flex: 1,
    });
    const toolbar = ref<Toolbar>({
      items: [
        {
          label: "Upload File",
          icon: "document",
          alignment: "right",
          action: (params: ToolbarItemActionParams) => {
            const curr = params.api.getGridOption("activeOverlay");
            params.api.setGridOption(
              "activeOverlay",
              curr === "agFileInputOverlay" ? undefined : "agFileInputOverlay",
            );
          },
        },
      ],
    });
    const rowData = ref<any[]>(null);

    const onLoadSampleData: () => void = () => {
      const select = document.getElementById("sampleData") as HTMLSelectElement;
      const value = select.value;
      if (!value) return;
      if (value.endsWith(".xlsx")) {
        fetch(`https://www.ag-grid.com/example-assets/${value}`)
          .then((response) => response.arrayBuffer())
          .then((data: ArrayBuffer) => {
            const workbook = XLSX.read(new Uint8Array(data));
            gridApi.value.updateGridOptions({
              activeOverlay: undefined,
              rowData: parseWorkbook(workbook),
            });
          });
      } else {
        fetch(`https://www.ag-grid.com/example-assets/${value}`)
          .then((response) => response.json())
          .then((rows) => {
            gridApi.value.updateGridOptions({
              activeOverlay: undefined,
              rowData: rows,
            });
          });
      }
    };
    const onGridReady = (params: GridReadyEvent) => {
      gridApi.value = params.api;
    };
    const processFileInput: (params: ProcessFileInputParams) => void = (
      params: ProcessFileInputParams,
    ) => {
      const file = params.files[0];
      if (!file) return;
      const reader = new FileReader();
      reader.onerror = () => {
        params.fail("Failed to read file");
      };
      reader.onload = (e) => {
        try {
          const workbook = XLSX.read(
            new Uint8Array(e.target?.result as ArrayBuffer),
          );
          params.success(parseWorkbook(workbook));
        } catch (error) {
          console.error(error);
          params.fail("Failed to parse file");
        }
      };
      reader.readAsArrayBuffer(file);
    };

    return {
      gridApi,
      processFileInput,
      defaultColDef,
      toolbar,
      rowData,
      onGridReady,
      onLoadSampleData,
    };
  },
});

const app = createApp(VueExample);
app.mount("#app");
```

[Live example: Auto-Generate Columns](https://www.ag-grid.com/examples/auto-generate-columns/file-drop-overlay/vue3)
