---
title: "Auto-Generate Columns"
framework: angular
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 { Component } from "@angular/core";
import { AgGridAngular } from "ag-grid-angular";
import {
  AutoGenerateColumnDefsOptions,
  AutoGenerateColumnsModule,
  ClientSideRowModelModule,
  GridApi,
  GridOptions,
  GridReadyEvent,
  ModuleRegistry,
  enableDevValidations,
} from "ag-grid-community";
if (process.env.NODE_ENV !== "production") {
  enableDevValidations();
}

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

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<ag-grid-angular
    style="width: 100%; height: 100%;"
    [autoGenerateColumnDefs]="true"
    [rowData]="rowData"
  /> `,
})
export class AppComponent {
  rowData: 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 },
    },
  ];
}
```

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

```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/angular-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 { Component } from "@angular/core";
import { AgGridAngular } from "ag-grid-angular";
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,
]);

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="example-wrapper">
    <div class="example-header">
      <label>
        objectValues:
        <select id="objectValues" (change)="onObjectValues()">
          <option value="group">group</option>
          <option value="flatten">flatten</option>
          <option value="skip">skip</option>
        </select>
      </label>
      <label>
        arrayValues:
        <select id="arrayValues" (change)="onArrayValues()">
          <option value="primitives">primitives</option>
          <option value="include">include</option>
          <option value="skip">skip</option>
        </select>
      </label>
      <label>
        nullishValues:
        <select id="nullishValues" (change)="onNullishValues()">
          <option value="include">include</option>
          <option value="skip">skip</option>
        </select>
      </label>
    </div>
    <ag-grid-angular
      style="width: 100%; height: 100%;"
      [rowData]="rowData"
      [autoGenerateColumnDefs]="autoGenerateColumnDefs"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  private gridApi!: GridApi;

  rowData: 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,
    },
  ];
  autoGenerateColumnDefs: boolean | AutoGenerateColumnDefsOptions = {
    ...config,
  };

  onObjectValues(): void {
    const value = (document.getElementById("objectValues") as HTMLSelectElement)
      .value;
    config.objectValues =
      value as AutoGenerateColumnDefsOptions["objectValues"];
    this.gridApi.setGridOption("autoGenerateColumnDefs", { ...config });
  }

  onArrayValues(): void {
    const value = (document.getElementById("arrayValues") as HTMLSelectElement)
      .value;
    config.arrayValues = value as AutoGenerateColumnDefsOptions["arrayValues"];
    this.gridApi.setGridOption("autoGenerateColumnDefs", { ...config });
  }

  onNullishValues(): void {
    const value = (
      document.getElementById("nullishValues") as HTMLSelectElement
    ).value;
    config.nullishValues =
      value as AutoGenerateColumnDefsOptions["nullishValues"];
    this.gridApi.setGridOption("autoGenerateColumnDefs", { ...config });
  }

  onGridReady(params: GridReadyEvent) {
    this.gridApi = params.api;
  }
}

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

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

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

#### Customising Columns

```ts
import { Component } from "@angular/core";
import { AgGridAngular } from "ag-grid-angular";
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,
]);

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<ag-grid-angular
    style="width: 100%; height: 100%;"
    [processAutoGeneratedColumnDefs]="processAutoGeneratedColumnDefs"
    [autoGenerateColumnDefs]="true"
    [columnTypes]="columnTypes"
    [defaultColDef]="defaultColDef"
    [rowData]="rowData"
  /> `,
})
export class AppComponent {
  processAutoGeneratedColumnDefs: ProcessAutoGeneratedColumnDefs = (params) => {
    forEachColDef(params.columnDefs, (colDef) => {
      if (colDef.field?.includes("profit")) {
        colDef.type = "currencyColumn";
      }
    });
    return params.columnDefs;
  };
  columnTypes: ColTypeDefs = {
    currencyColumn: {
      valueFormatter: (params) =>
        params.value == null ? "" : "£" + params.value.toLocaleString(),
      filter: "agNumberColumnFilter",
    },
  };
  defaultColDef: ColDef = {
    flex: 1,
  };
  rowData: 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 },
  ];
}
```

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

## 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/angular-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 { Component } from "@angular/core";
import { AgGridAngular } from "ag-grid-angular";
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;

@Component({
  selector: "my-app",
  standalone: true,
  imports: [AgGridAngular],
  template: `<div class="example-wrapper">
    <div class="example-header">
      <label>
        Sample data:
        <select id="sampleData" (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-angular
      style="width: 100%; height: 100%;"
      [processFileInput]="processFileInput"
      [autoGenerateColumnDefs]="true"
      [defaultColDef]="defaultColDef"
      [toolbar]="toolbar"
      [rowData]="rowData"
      (gridReady)="onGridReady($event)"
    />
  </div> `,
})
export class AppComponent {
  private gridApi!: GridApi;

  defaultColDef: ColDef = {
    minWidth: 80,
    flex: 1,
  };
  toolbar: 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",
          );
        },
      },
    ],
  };
  rowData!: any[];

  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));
          this.gridApi.updateGridOptions({
            activeOverlay: undefined,
            rowData: parseWorkbook(workbook),
          });
        });
    } else {
      fetch(`https://www.ag-grid.com/example-assets/${value}`)
        .then((response) => response.json())
        .then((rows) => {
          this.gridApi.updateGridOptions({
            activeOverlay: undefined,
            rowData: rows,
          });
        });
    }
  }

  onGridReady(params: GridReadyEvent) {
    this.gridApi = params.api;
  }

  processFileInput = (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);
  };
}

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

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