---
title: "Auto-Generate Columns"
framework: react
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

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  AutoGenerateColumnDefsOptions,
  AutoGenerateColumnsModule,
  ClientSideRowModelModule,
  GridApi,
  GridOptions,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [ClientSideRowModelModule, AutoGenerateColumnsModule];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>([
    {
      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 },
    },
  ]);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact rowData={rowData} autoGenerateColumnDefs={true} />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

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

```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/react-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

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./styles.css";
import {
  AutoGenerateColumnDefsOptions,
  AutoGenerateColumnsModule,
  ClientSideRowModelModule,
  GridApi,
  GridOptions,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [ClientSideRowModelModule, AutoGenerateColumnsModule];

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

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>([
    {
      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 = useMemo<
    boolean | AutoGenerateColumnDefsOptions
  >(() => {
    return { ...config };
  }, []);

  const onObjectValues = useCallback((): void => {
    const value = (document.getElementById("objectValues") as HTMLSelectElement)
      .value;
    config.objectValues =
      value as AutoGenerateColumnDefsOptions["objectValues"];
    gridRef.current!.api.setGridOption("autoGenerateColumnDefs", { ...config });
  }, [config]);

  const onArrayValues = useCallback((): void => {
    const value = (document.getElementById("arrayValues") as HTMLSelectElement)
      .value;
    config.arrayValues = value as AutoGenerateColumnDefsOptions["arrayValues"];
    gridRef.current!.api.setGridOption("autoGenerateColumnDefs", { ...config });
  }, [config]);

  const onNullishValues = useCallback((): void => {
    const value = (
      document.getElementById("nullishValues") as HTMLSelectElement
    ).value;
    config.nullishValues =
      value as AutoGenerateColumnDefsOptions["nullishValues"];
    gridRef.current!.api.setGridOption("autoGenerateColumnDefs", { ...config });
  }, [config]);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div className="example-header">
            <label>
              objectValues:
              <select id="objectValues" onChange={onObjectValues}>
                <option value="group">group</option>
                <option value="flatten">flatten</option>
                <option value="skip">skip</option>
              </select>
            </label>
            <label>
              arrayValues:
              <select id="arrayValues" onChange={onArrayValues}>
                <option value="primitives">primitives</option>
                <option value="include">include</option>
                <option value="skip">skip</option>
              </select>
            </label>
            <label>
              nullishValues:
              <select id="nullishValues" onChange={onNullishValues}>
                <option value="include">include</option>
                <option value="skip">skip</option>
              </select>
            </label>
          </div>

          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              rowData={rowData}
              autoGenerateColumnDefs={autoGenerateColumnDefs}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

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

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/react-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/react-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/react-data-grid/column-definitions/#column-types) to apply a `currencyColumn` type to any column whose field contains `"profit"`:

#### Customising Columns

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
  AutoGenerateColumnDefsOptions,
  AutoGenerateColumnsModule,
  ClientSideRowModelModule,
  ColDef,
  ColTypeDefs,
  GridApi,
  GridOptions,
  ModuleRegistry,
  NumberFilterModule,
  ProcessAutoGeneratedColumnDefs,
  enableDevValidations,
  forEachColDef,
} from "ag-grid-community";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  AutoGenerateColumnsModule,
  NumberFilterModule,
];

const GridExample = () => {
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
  const [rowData, setRowData] = useState<any[]>([
    { 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 processAutoGeneratedColumnDefs = useCallback((params) => {
    forEachColDef(params.columnDefs, (colDef) => {
      if (colDef.field?.includes("profit")) {
        colDef.type = "currencyColumn";
      }
    });
    return params.columnDefs;
  }, []);
  const columnTypes = useMemo<ColTypeDefs>(() => {
    return {
      currencyColumn: {
        valueFormatter: (params) =>
          params.value == null ? "" : "£" + params.value.toLocaleString(),
        filter: "agNumberColumnFilter",
      },
    };
  }, []);
  const defaultColDef = useMemo<ColDef>(() => {
    return {
      flex: 1,
    };
  }, []);

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div style={gridStyle}>
          <AgGridReact
            rowData={rowData}
            processAutoGeneratedColumnDefs={processAutoGeneratedColumnDefs}
            autoGenerateColumnDefs={true}
            columnTypes={columnTypes}
            defaultColDef={defaultColDef}
          />
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

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

## 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/react-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

```tsx
"use client";

import React, {
  useCallback,
  useMemo,
  useRef,
  useState,
  StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import "./styles.css";
import {
  AutoGenerateColumnDefsOptions,
  AutoGenerateColumnsModule,
  ClientSideRowModelModule,
  ColDef,
  GridApi,
  GridOptions,
  ModuleRegistry,
  NumberFilterModule,
  ProcessFileInputParams,
  TextFilterModule,
  Toolbar,
  ToolbarItemActionParams,
  enableDevValidations,
} from "ag-grid-community";
import { ToolbarModule } from "ag-grid-enterprise";

if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

const modules = [
  ClientSideRowModelModule,
  AutoGenerateColumnsModule,
  TextFilterModule,
  NumberFilterModule,
  ToolbarModule,
];

declare let XLSX: any;

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

const GridExample = () => {
  const gridRef = useRef<AgGridReact>(null);
  const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
  const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);

  const defaultColDef = useMemo<ColDef>(() => {
    return {
      minWidth: 80,
      flex: 1,
    };
  }, []);
  const toolbar = useMemo<Toolbar>(() => {
    return {
      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 onLoadSampleData = useCallback((): 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));
          gridRef.current!.api.updateGridOptions({
            activeOverlay: undefined,
            rowData: parseWorkbook(workbook),
          });
        });
    } else {
      fetch(`https://www.ag-grid.com/example-assets/${value}`)
        .then((response) => response.json())
        .then((rows) => {
          gridRef.current!.api.updateGridOptions({
            activeOverlay: undefined,
            rowData: rows,
          });
        });
    }
  }, []);

  const processFileInput = useCallback(
    (params: ProcessFileInputParams): void => {
      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);
    },
    [FileReader],
  );

  return (
    <AgGridProvider modules={modules}>
      <div style={containerStyle}>
        <div className="example-wrapper">
          <div className="example-header">
            <label>
              Sample data:
              <select id="sampleData" onChange={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>

          <div style={gridStyle}>
            <AgGridReact
              ref={gridRef}
              processFileInput={processFileInput}
              autoGenerateColumnDefs={true}
              defaultColDef={defaultColDef}
              toolbar={toolbar}
            />
          </div>
        </div>
      </div>
    </AgGridProvider>
  );
};

const root = createRoot(document.getElementById("root")!);
root.render(
  <StrictMode>
    <GridExample />
  </StrictMode>,
);
```

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