DEV Community

Malloc72P
Malloc72P

Posted on

Building a Full-Stack Data Grid App with Next.js, Prisma, and AG Grid

TL;DR

  • Build a complete CRUD data grid app using Next.js (Server Components + Server Actions), Prisma ORM (type-safe DB access), and AG Grid (inline editing, sorting, virtual scroll).
  • Server Components fetch data on the server; Server Actions let clients call server-side functions like regular async functions — no REST API needed.
  • Prisma provides auto-generated TypeScript types from your schema, making DB queries fully type-safe.
  • AG Grid's applyTransaction API enables optimistic updates — the UI updates instantly, and rolls back on failure.

Key Concepts

Next.js: Server Components & Server Actions

Server Components run on the server and can call business logic directly:

// app/page.tsx — Server Component
export default async function Home() {
  const orders = await getOrders(); // Direct DB call
  return <OrderGrid orders={orders} />;
}
Enter fullscreen mode Exit fullscreen mode

Server Actions let client components call server functions with a simple 'use server' directive:

'use server';

export async function createOrderAction(input: CreateOrderInput) {
  return createOrder(input);
}
Enter fullscreen mode Exit fullscreen mode

The client calls it like a normal function — Next.js handles the HTTP layer internally.

Prisma ORM: Type-Safe Database Access

Define your schema in Prisma's DSL, then generate a fully typed client:

model Order {
  id    Int @id @default(autoincrement())
  price Int
  qty   Int
}
Enter fullscreen mode Exit fullscreen mode

CRUD operations are concise and type-safe:

// Create
await prisma.order.create({ data: { price, qty } });

// Read with filters
await prisma.order.findMany({
  where: { price: { gt: 1000 } },
  skip: 20,
  take: 20,
});

// Update
await prisma.order.update({ where: { id }, data: { price, qty } });

// Delete
await prisma.order.delete({ where: { id } });
Enter fullscreen mode Exit fullscreen mode

AG Grid: Optimistic Updates with applyTransaction

The optimistic update pattern — update the UI first, then sync with the server:

async function handleCreate() {
  const tempId = -Date.now();
  const tempRow: Order = { id: tempId, price: 0, qty: 0 };

  // Optimistic: add temp row immediately
  gridRef.current?.api.applyTransaction({ add: [tempRow] });

  try {
    const created = await createOrderAction({ price: 0, qty: 0 });
    // Replace temp row with real data
    gridRef.current?.api.applyTransaction({
      remove: [tempRow],
      add: [created],
    });
  } catch {
    // Rollback on failure
    gridRef.current?.api.applyTransaction({ remove: [tempRow] });
  }
}
Enter fullscreen mode Exit fullscreen mode

The same pattern applies to update (rollback cell value on failure) and delete (re-add the row on failure).

Code Examples

Setting up the AG Grid component with inline editing and a delete button:

const colDefs: ColDef<Order>[] = useMemo(() => [
  { field: 'id', editable: false, sort: 'asc' },
  { field: 'price', editable: true },
  { field: 'qty', editable: true },
  {
    headerName: '',
    width: 100,
    cellRenderer: (p: ICellRendererParams<Order>) => (
      <button onClick={() => handleDelete(p.data!)}>Delete</button>
    ),
  },
], []);

<AgGridReact
  ref={gridRef}
  rowData={orders}
  columnDefs={colDefs}
  getRowId={(p) => String(p.data.id)}
  onCellValueChanged={handleCellValueChanged}
/>
Enter fullscreen mode Exit fullscreen mode

This is a summary of my original 3-part series written in Korean.
For the full articles with step-by-step setup instructions, check out the originals:

👉 Part 1: Next.js Basics
👉 Part 2: Prisma ORM Setup & CRUD
👉 Part 3: AG Grid & Optimistic Updates

Top comments (4)

Collapse
 
sylwiavargas profile image
Sylwia Vargas

Interesting! What inspired you to write this post? 👀

Collapse
 
malloc72p profile image
Malloc72P

Thanks for asking! I built this app for a side project and thought the combination of Next.js Server Actions + Prisma + AG Grid worked really well together. I originally wrote a detailed 3-part series about it on my Korean blog, so I figured I'd share a condensed version here for the English-speaking community too 😉

Collapse
 
sylwiavargas profile image
Sylwia Vargas

Oh that's really cool. Was there an app you were building or was it just playing with the infra for you? I'd love to see a demo if you built something!

Thread Thread
 
malloc72p profile image
Malloc72P

Thanks for the interest! It started as a proof-of-concept for a work project — we needed an inline-editable data grid with server-side persistence. I don’t have a live demo up right now, but I’m thinking about deploying one. I’ll update this post if I do!