Migrating from AG Grid to SvGrid

If you tried AG Grid on a Svelte 5 project - via ag-grid-svelte, the old ag-grid-community/svelte, or a hand-rolled wrapper - you probably hit the same friction everyone hits: the bridge between AG Grid's React/Angular-first API and Svelte 5 runes is brittle, the bundle is heavy, and the Enterprise pricing only makes sense at scale.

Facts, checked 12 Sep 2026. ag-grid-community 36.1.0, MIT, last published 5 Aug 2026, 12,400,000 npm downloads in the 30 days to 10 Sep 2026. @svgrid/grid 3.0.3, MIT, last published 11 Sep 2026, 16,900 npm downloads in the same window. Bundle, minified and gzipped, each package built alone with Svelte external: SvGrid 3.0.3 84.5 KB JS + 9.5 KB CSS (measured 12 Sep 2026); ag-grid-community 36.1.0 317.5 KB JS, no separate stylesheet (measured 12 Sep 2026). AG Grid pricing, as its site states it: AG Grid Community is free under MIT. AG Grid Enterprise is listed at $999 USD per developer with one year of updates and Zendesk support; the Enterprise Bundle with AG Charts Enterprise is $1,498 USD per developer (https://www.ag-grid.com/license-pricing/, read 12 Sep 2026). SvGrid: MIT core; @svgrid/enterprise from $599 per developer per year. Side by side, with sources: SvGrid vs AG Grid (community + enterprise).

This page is a 30-minute migration recipe from AG Grid to SvGrid. It covers what maps 1:1, what's different by design, and what you'll lose. We tell you when not to switch at the bottom.

TL;DR

AG Grid Community AG Grid Enterprise SvGrid Community @svgrid/enterprise
Licence MIT Commercial, per developer (the price is in the facts box above) MIT $599/dev/yr (single app) or $999/dev/yr (multi app)
Svelte 5 native No (community-built integration) No (community-built integration) Yes Yes
Bundle (gzipped) measured, in the facts box above not measured (licence) measured, in the facts box above lazy-loaded subpaths
Sorting / filtering Yes Yes Yes (in Community)
Row grouping + aggregation No (Enterprise) Yes Yes (free) (in Community)
Master/detail, tree, range select No (Enterprise) Yes Yes (free) (in Community)
Set filter / Excel-style filter menu No (Enterprise) Yes Yes (free) (in Community)
Server-side row model No (Enterprise) Yes Yes (free) (in Community)
Integrated charts No (Enterprise) Yes, AG Charts Yes (free) (in Community)
CSV export Yes (API) Yes Yes, with TSV and JSON (in Community)
Excel export No Yes No Yes
PDF / styled-HTML export, print No No No Yes
Pivot tables No Yes No Yes
MCP server for AI assistants Yes, ag-mcp Yes Yes, @svgrid/mcp (in Community)
In-grid AI helpers No No Yes (bring your own model) (in Community)

SvGrid Community gives you most of what AG Grid sells as Enterprise for free, and @svgrid/enterprise adds Excel, PDF and print output, import and pivot tables per developer per year. Compare what each paid tier adds before comparing prices; both are in the facts box. The trade-offs are Svelte-only and a much smaller ecosystem. Every AG Grid cell above follows ag-grid.com's own pages; the dated list is on the SvGrid vs AG Grid page.

Mental model - what changes

AG Grid is one big object you configure declaratively. SvGrid is a headless engine (createSvGrid) with an optional render component (<SvGrid>) on top - the same split TanStack Table made popular. You can use either layer; most projects use the render component.

Every example below runs against this setup:

<script lang="ts">
  import { SvGrid, tableFeatures, rowSortingFeature, columnFilteringFeature, type ColumnDef } from '@svgrid/grid'

  type Row = { id: number; make: string; model: string; price: number }

  const features = tableFeatures({ rowSortingFeature, columnFilteringFeature })

  let rows = $state<Row[]>([
    { id: 1, make: 'Toyota', model: 'Celica', price: 35000 },
    { id: 2, make: 'Ford',   model: 'Mondeo', price: 32000 },
    { id: 3, make: 'Porsche', model: 'Boxster', price: 72000 },
  ])
  const data = rows

  const columns: ColumnDef<typeof features, Row>[] = [
    { field: 'make',  header: 'Make' },
    { field: 'model', header: 'Model' },
    { field: 'price', header: 'Price', format: { type: 'currency', currency: 'USD' } },
  ]
</script>
<!-- AG Grid (via a Svelte wrapper) -->
<AgGridSvelte
  gridOptions={{
    rowData: rows,
    columnDefs: columns,
    onGridReady: (params) => (gridApi = params.api),
  }}
/>

<!-- SvGrid -->
<SvGrid
  data={rows}
  columns={columns}
  features={features}
  onApiReady={(api) => (gridApi = api)}
/>

Three things to note:

  1. No giant gridOptions blob. Each capability is a top-level prop.
  2. Features are opt-in. You pass a features object built with tableFeatures({...}) - only the features you list ship JS.
  3. onApiReady gives you a typed SvGridApi that is roughly the AG Grid gridApi equivalent (see the API-mapping table below).

Column definitions - direct translation

The shapes are similar enough that you can usually translate by hand without thinking too hard.

// AG Grid
const columnDefs: ColDef[] = [
  { field: 'name', headerName: 'Name', sortable: true, filter: true, width: 200 },
  { field: 'price', headerName: 'Price', type: 'numericColumn',
    valueFormatter: ({ value }) => `$${value.toFixed(2)}` },
  { field: 'date', headerName: 'Date',
    valueGetter: ({ data }) => new Date(data.date).toISOString().slice(0, 10) },
  { field: 'status', headerName: 'Status',
    cellRenderer: StatusCellRenderer,
    cellRendererParams: { onChange: handleStatusChange } },
]
// SvGrid
import { renderComponent, type ColumnDef } from '@svgrid/grid'
import StatusCell from './StatusCell.svelte'

const columns: ColumnDef<typeof features, Row>[] = [
  { field: 'name', header: 'Name', width: 200 }, // sortable + filterable by default
  { field: 'price', header: 'Price',
    format: { type: 'currency', currency: 'USD' } },
  { field: 'date', header: 'Date',
    format: { type: 'date', pattern: 'y-m-d' } },
  { field: 'status', header: 'Status',
    cell: renderComponent(StatusCell, (ctx) => ({
      value: ctx.getValue(),
      onChange: handleStatusChange,
    })),
  },
]

Property mapping

AG Grid SvGrid Notes
field field Same.
headerName header Accepts a string or a snippet/component.
width width Same.
minWidth / maxWidth minWidth / maxWidth Same.
sortable: true (default) Sorting is on when rowSortingFeature is registered.
filter: true (default) Filtering is on when columnFilteringFeature is registered.
valueFormatter format: { ... } Built-in types: number, currency, percent, date. For custom, use cell.
valueGetter fieldFn Returns the value for sorting/filtering.
cellRenderer + cellRendererParams cell: renderComponent(C, ctx => props) One call, type-checked.
cellEditor: 'agTextCellEditor' editorType: 'text' Built-in: text, number, checkbox, date.
editable: true enableInlineEditing prop on <SvGrid> Per-grid, not per-column. (Per-column control on the roadmap.)
pinned: 'left' / 'right' Right-click column menu → Pin Set programmatically via the api.
rowGroup: true Via setGroupBy([colId]) See Grouping below.
aggFunc: 'sum' aggregate: 'sum' Built-in: sum, avg, min, max, count.

Feature registration - the one new thing

AG Grid auto-enables most features; you turn them off. SvGrid is the opposite - features are opt-in. The result is a smaller bundle.

import {
  tableFeatures,
  rowSortingFeature,
  columnFilteringFeature,
  columnGroupingFeature,
  rowExpandingFeature,
  rowPaginationFeature,
  rowSelectionFeature,
} from '@svgrid/grid'

const features = tableFeatures({
  rowSortingFeature,
  columnFilteringFeature,
  rowSelectionFeature,
  // omit any you don't need - their code won't ship
})

Pass features to <SvGrid> once. From then on the grid behaves like AG Grid's enableSorting, enableFilter, rowSelection, etc. are all on for the registered features.

API mapping (gridApiSvGridApi)

You get the SvGrid API from onApiReady (equivalent to AG Grid's onGridReady).

AG Grid gridApi.X() SvGrid api.X()
setRowData(rows) (declarative - just update data prop)
addRow(row) / applyTransaction({ add: [row] }) api.addRow(row) / api.addRows(rows)
applyTransaction({ remove: [row] }) api.removeRow(rowIndex)
getValue(colId, rowNode) api.getCellValue(rowIndex, columnId)
setValue(...) api.setCellValue(rowIndex, columnId, value)
setColumnVisible(colId, visible) api.setColumnVisible(columnId, visible)
getSortModel() / setSortModel() api.setSort(columnId, 'asc'|'desc'|null)
setFilterModel({...}) api.setFilter(columnId, { operator, value })
getDisplayedRowAtIndex(i) / forEachNodeAfterFilterAndSort(...) api.getDisplayedRows()
getModel() (raw rows) api.getData()

Common patterns

Sorting + filtering + pagination (the 80% case)

<script lang="ts">
  import {
    SvGrid,
    tableFeatures,
    rowSortingFeature,
    columnFilteringFeature,
    rowPaginationFeature,
  } from '@svgrid/grid'

  const features = tableFeatures({
    rowSortingFeature,
    columnFilteringFeature,
    rowPaginationFeature,
  })
</script>

<SvGrid
  data={rows}
  columns={columns}
  features={features}
  showPagination
  showColumnFilters
/>

AG Grid equivalent: gridOptions: { defaultColDef: { sortable: true, filter: true }, pagination: true }.

Cell editing with persistence

<script lang="ts">
  function onCellValueChange(e: { rowIndex: number; columnId: string; value: unknown }) {
    // Persist however you like (fetch to backend, optimistic local update, etc.)
    console.log('cell changed', e)
  }
</script>

<SvGrid
  data={rows}
  columns={columns}
  features={features}
  enableInlineEditing
  onCellValueChange={onCellValueChange}
/>

AG Grid equivalent: onCellValueChanged: ({ data, colDef, newValue, oldValue }) => .... SvGrid's event payload is column-id + row-index based rather than node-based; the row data is yours to mutate (or not) on the rows array you passed in.

Grouping + aggregation

<script lang="ts">
  import {
    SvGrid,
    tableFeatures,
    columnGroupingFeature,
    rowSortingFeature,
    rowExpandingFeature,
  } from '@svgrid/grid'

  const features = tableFeatures({
    rowSortingFeature,
    columnGroupingFeature,
    rowExpandingFeature,
  })

  const columns = [
    { field: 'department', header: 'Department' },
    { field: 'team',       header: 'Team' },
    { field: 'salary',     header: 'Salary', aggregate: 'sum',
      format: { type: 'currency', currency: 'USD' } },
  ]

  function setGroup(api) {
    api.setGroupBy(['department', 'team'])
  }
</script>

<SvGrid
  data={rows}
  columns={columns}
  features={features}
  showGroupingControls
  onApiReady={setGroup}
/>

AG Grid Enterprise's rowGroupPanelShow: 'always' + aggFunc: 'sum' translates 1:1.

Master / detail

AG Grid Enterprise feature; free in SvGrid Community. See demo 08 for the exact pattern.

Server-side data

AG Grid uses an IServerSideDatasource interface. SvGrid uses externalSort + externalFilter props - your code keeps full control over the query, and the grid records UI state but doesn't re-order rows locally. See demo 09.

Excel / PDF export

AG Grid: gridApi.exportDataAsExcel({...}) (Enterprise-only). SvGrid: install @svgrid/enterprise, call api.exportData({ format: 'xlsx', ... }). See Data export and printing.

import { installEnterprise, setLicenseKey } from '@svgrid/enterprise'
setLicenseKey('SVENTERPRISE-...')   // your Enterprise key

// inside onApiReady:
const pro = installEnterprise(api)
await pro.exportData({ format: 'xlsx', filename: 'orders' })

Gotchas - things that don't translate directly

1. Per-column editable: true

Editing is switched on at the grid level (enableInlineEditing) and narrowed per column with editable: boolean | (ctx) => boolean on the column definition, so AG Grid's per-column flag and its callback form both map directly. What does not map is AG Grid's editable on a column group: set it on each child column.

2. Column drag-to-reorder

Header drag is enableColumnReorder on <SvGrid>; setColumnOrder on the API does the same from code. See column moving for the events.

3. AG Grid valueGetter chains

AG Grid's valueGetter can read other column values via the API. In SvGrid, fieldFn only receives the row; if you need cross-column computed values, do it in the cell renderer with ctx.row.original or compute the derived value upstream and store it in the row.

4. cellClass / rowClass callbacks

On the roadmap. For now, render a wrapper element in your cell snippet with the conditional class.

5. The Status Bar / Side Bar / Tool Panels

AG Grid's chrome (status bar with row count, side bar with filters and columns panels) doesn't exist in SvGrid - build it as plain Svelte markup around the grid. Most teams build their own anyway because AG Grid's defaults rarely match a polished design system.

6. Set filter (the Excel-style funnel popup)

SvGrid ships an Excel-style filter menu (free in Community). API surface is similar but not identical - see Set filter.

When NOT to migrate

Be honest. Stay on AG Grid if you:

If none of those apply: switching drops a per-developer Enterprise licence for features that are in SvGrid's MIT core, cuts the bundle by the difference in the facts box above, and gives you a Svelte-native API that plays well with runes.

Step-by-step migration

A typical migration of a single grid takes 1-3 hours:

  1. Install - pnpm add @svgrid/grid (and @svgrid/enterprise if you need export).
  2. Translate columnDefs - use the mapping table above. Most columns are 1:1.
  3. Wrap features - figure out which AG Grid features you actually use; register only those in tableFeatures({...}).
  4. Swap the component - <AgGridSvelte gridOptions={...}><SvGrid data={rows} columns={columns} features={features}>.
  5. Move event handlers - AG Grid onCellValueChanged → SvGrid onCellValueChange (signature differs slightly, see above).
  6. Move API calls - AG Grid gridApi.X() → SvGrid api.X() per the API table.
  7. Test interactions - sort, filter, edit, select. Most "just works."
  8. Remove ag-grid-* packages - pnpm remove ag-grid-community ag-grid-svelte etc. Inspect your bundle to confirm the drop; the facts box above has both measured sizes.

Need help migrating?

Enterprise customers get migration help included with the support plan (architecture review, port one grid for you as a reference). Email [email protected] after purchase, or [email protected] for pre-sales questions.

Frequently asked questions

Is SvGrid a drop-in replacement for AG Grid in Svelte?

Not a literal drop-in - there is no ag-grid-svelte shim to swap. But the concepts map closely: column definitions, row models, sorting, filtering, grouping, and an imperative API all have direct SvGrid equivalents, so most teams port a grid in 30 minutes to a day. It is a configuration translation, not a rewrite.

What is the SvGrid equivalent of AG Grid Enterprise?

@svgrid/enterprise. It adds Excel/PDF/styled-HTML export (CSV, TSV and JSON export are already free in the grid), a printable view, pivot tables and data import. The in-grid AI helpers are free in @svgrid/grid. It is licensed per developer ($599 single-app / $999 multi-app), and the Community package is MIT-licensed and free for commercial use.

Does SvGrid use Svelte 5 runes, or is it a wrapper?

It is Svelte-5-native. State is $state / $derived / $effect and cells render through Svelte snippets - there is no React or Angular core underneath and no framework bridge to keep in sync.

Will my AG Grid bundle size shrink?

Almost always. The facts box at the top of this page has both packages measured the same way on the same date: the full SvGrid render component with its stylesheet against createGrid with every AG Grid Community module registered. You add @svgrid/enterprise features only where you import them, and the headless core on its own is a small fraction of the render component.

More examples

AG Grid ↔ sv-grid side-by-side

Two real grids over the same dataset: the installed AG Grid Community on the left, sv-grid on the right. Same global filter drives both. Source code panels for either side.

Open the live example: AG Grid ↔ sv-grid side-by-side (Integrations)

See also

Live examples

  • AG Grid ↔ sv-grid side-by-side - Two real grids over the same dataset: AG Grid Community v35 on the left, sv-grid on the right. Same global filter drives both. Source code panels for either side.
  • Tree + master/detail - Hierarchical file-system rows and an order/line-item master-detail view.
  • Server-side data - Sort/filter/page round-tripped to a mock endpoint with debounce + cancel.

Related articles