Getting started

This is the gentlest path into SvGrid Studio. By the end you will have a real, working Customers screen - a grid you can sort, filter, and page, with a create / edit form and delete - running on your machine. No prior experience with SvGrid is assumed.

If you would rather just click around first, open a live demo - no install needed:


Two ways to build - pick yours

Build a data app in four no-code steps: open the designer, start from a sample or your database, arrange it visually, then generate the app.

This is the visual designer - a screens list on the left, your data previewed live in the middle, and simple property panels on the right. You point, click, and press Generate:

The visual app designer with a customer grid previewed live and a properties panel for the screen and its fields.

The two paths produce the same result; the visual designer just writes the code for you.


What you need

You do not need a database to start - the first screen below runs on in-memory data. You can point it at PostgreSQL, Supabase, MySQL, and others later without changing the UI.


Step 1 - Install

Inside your app folder:

npm i @svgrid/grid @svgrid/enterprise

Step 2 - Describe your data once

Everything in Studio flows from one EntitySchema - a plain object that lists your fields and their types. This single object drives the grid columns, the edit form, and validation. Create src/lib/customers.ts:

import type { EntitySchema } from '@svgrid/enterprise'

export type Customer = {
  id: string
  name: string
  email: string
  tier: 'free' | 'pro' | 'enterprise'
  mrr: number
  active: boolean
}

export const customersSchema: EntitySchema<Customer> = {
  name: 'customers',
  label: 'Customer',
  idField: 'id',
  fields: [
    { field: 'id', type: 'text', primaryKey: true, readonly: true },
    { field: 'name', type: 'text', required: true, minLength: 2 },
    { field: 'email', type: 'text', label: 'Email', required: true, format: 'email' },
    { field: 'tier', type: 'enum', options: [
      { value: 'free', label: 'Free' },
      { value: 'pro', label: 'Pro' },
      { value: 'enterprise', label: 'Enterprise' },
    ] },
    { field: 'mrr', type: 'number', label: 'MRR ($)', min: 0 },
    { field: 'active', type: 'boolean' },
  ],
}

Every field option is explained in The EntitySchema.


Step 3 - Build the screen

Studio binds any data through one small contract, ServerDataSource (read + create + update + delete). For a first run, createInMemoryDataSource gives you that contract over a plain array - so the whole screen works before you have a database. Create src/routes/customers/+page.svelte:

<script lang="ts">
  import { SvGrid, createServerDataSource, type ServerState } from '@svgrid/grid'
  import { SvGridEditPanel, createInMemoryDataSource, schemaToColumns } from '@svgrid/enterprise'
  import { customersSchema, type Customer } from '$lib/customers'

  const seed: Customer[] = [
    { id: 'c1', name: 'Ada Lovelace', email: '[email protected]', tier: 'enterprise', mrr: 1200, active: true },
    { id: 'c2', name: 'Alan Turing', email: '[email protected]', tier: 'pro', mrr: 240, active: true },
    { id: 'c3', name: 'Grace Hopper', email: '[email protected]', tier: 'enterprise', mrr: 980, active: true },
  ]

  const columns = schemaToColumns(customersSchema)
  const source = createInMemoryDataSource(seed, customersSchema)

  let view = $state<ServerState<Customer>>({
    rows: [], total: 0, loading: false, saving: false, error: null,
    pageIndex: 0, pageSize: 10, pageCount: 1, sortModel: [], filterModel: {},
  })
  let editing = $state<Customer | null | undefined>(undefined)
  let genId = 4

  const controller = createServerDataSource(source, {
    pageSize: 10, optimistic: true, getRowId: (r) => r.id,
    onChange: (s) => (view = s),
  })
  controller.refresh()

  async function save({ mode, id, values }) {
    if (mode === 'create') { await controller.createRow({ id: `c${genId++}`, ...values }); controller.setPage(view.pageCount - 1) }
    else if (id) { await controller.updateRow(id, values) }
    editing = undefined
  }
</script>

<button onclick={() => (editing = null)}>+ New customer</button>

<SvGrid
  data={view.rows} {columns} loading={view.loading}
  fitColumns enableRowSummaries={false}
  sortable externalSort onSortingChange={(s) => controller.setSort(s)}
  filterable filterMode="row" externalFilter
  onFiltersChange={(f) => controller.setFilter({
    global: f.global || undefined,
    columns: Object.fromEntries(f.columns.map((c) => [c.id, { operator: c.operator, value: c.value, valueTo: c.valueTo, selectedValues: c.selectedValues }])),
  })}
  onRowClick={(e) => (editing = e.row)}
  showPagination externalPagination
  rowCount={view.total} pageIndex={view.pageIndex} pageSize={view.pageSize}
  onPaginationChange={({ pageIndex, pageSize }) => pageSize !== view.pageSize ? controller.setPageSize(pageSize) : controller.setPage(pageIndex)}
/>

{#if editing !== undefined}
  <SvGridEditPanel schema={customersSchema} row={editing} presentation="modal"
    onSubmit={save} onCancel={() => (editing = undefined)} />
{/if}

Step 4 - Run it

npm run dev

Open the URL it prints (usually http://localhost:5173) and go to /customers. You now have a working screen:

A CRUD screen generated by SvGrid Studio: sortable, filterable grid with a native pager, over a live data source.


Step 5 - Change something

Because the schema drives everything, changes are one edit. Add a field to customers.ts:

{ field: 'country', type: 'text', label: 'Country' },

Save. The grid gets a Country column and the edit form gets a Country input - no other change. That is the payoff of the single schema.


Where to go next

You have the whole shape now. The usual next steps:


See also