Skip to main content

Tech Stack

The Vendure Dashboard is built on a modern stack of technologies that provide a great developer experience and powerful capabilities for building custom extensions.

Core Technologies

React 19

The dashboard is built with React 19, giving you access to all the latest React features including:

  • React Compiler optimizations
  • Improved concurrent features
  • Actions and form handling improvements
  • Enhanced automatic batching
  • Better TypeScript support
  • New hooks like useOptimistic and useFormStatus
Tsx
import { useOptimistic, useFormStatus } from 'react';function OptimisticUpdateExample() {    const [optimisticState, addOptimistic] = useOptimistic(state, (currentState, optimisticValue) => {        // Return new state with optimistic update        return [...currentState, optimisticValue];    });    return (        <div>            {optimisticState.map(item => (                <div key={item.id}>{item.name}</div>            ))}        </div>    );}function SubmitButton() {    const { pending } = useFormStatus();    return (        <button type="submit" disabled={pending}>            {pending ? 'Saving...' : 'Save'}        </button>    );}

TypeScript

Full TypeScript support throughout the dashboard provides:

  • Type safety for your custom components
  • IntelliSense and autocomplete in your IDE
  • Compile-time error checking
  • Generated types from your GraphQL schema

Vite 6

Vite 6 powers the development experience with:

  • Lightning-fast hot module replacement (HMR)
  • Optimized build process with Rollup 4
  • Modern ES modules support
  • Rich plugin ecosystem
  • Environment API for better multi-environment support

UI Framework

Tailwind CSS v4

The dashboard uses Tailwind CSS v4 for styling:

  • Utility-first CSS framework
  • Improved performance with Rust-based engine
  • Enhanced CSS-first configuration
  • Responsive design system
  • Built-in dark mode support
  • Customizable design tokens
Tsx
// Example using Tailwind classesfunction MyComponent() {    return (        <div className="p-4 bg-white dark:bg-gray-800 rounded-lg shadow-md">            <h2 className="text-lg font-semibold text-gray-900 dark:text-white">My Custom Component</h2>        </div>    );}

Shadcn/ui

Built on top of Radix UI primitives, Shadcn/ui provides:

  • Accessible components out of the box
  • Consistent design system
  • Customizable component library
  • Copy-and-paste component approach
Tsx
import { Button, Input, Card } from '@vendure/dashboard';function MyForm() {    return (        <Card className="p-6">            <Input placeholder="Enter your text" />            <Button className="mt-4">Submit</Button>        </Card>    );}

Data Layer: TanStack Query

TanStack Query v5 handles all data fetching and server state management:

  • Automatic caching and synchronization
  • Background updates
  • Optimistic updates
  • Error handling and retry logic
Tsx
import { useQuery } from '@tanstack/react-query';import { graphql } from '@/gql';const getProductsQuery = graphql(`    query GetProducts {        products {            items {                id                name                slug            }        }    }`);function ProductList() {    const { data, isLoading, error } = useQuery({        queryKey: ['products'],        queryFn: () => client.request(getProductsQuery),    });    if (isLoading) return <div>Loading...</div>;    if (error) return <div>Error: {error.message}</div>;    return (        <ul>            {data.products.items.map(product => (                <li key={product.id}>{product.name}</li>            ))}        </ul>    );}

Routing: TanStack Router

TanStack Router provides type-safe routing with:

  • File-based routing
  • 100% type-safe navigation
  • Automatic route validation
  • Search params handling
  • Built-in caching and preloading
  • Route-level code splitting
Tsx
import { Link, useNavigate } from '@tanstack/react-router';function Navigation() {    const navigate = useNavigate();    return (        <div>            <Link to="/products">Products</Link>            <button onClick={() => navigate({ to: '/customers' })}>Go to Customers</button>        </div>    );}

Forms: React Hook Form

React Hook Form provides powerful form handling with:

  • Minimal re-renders
  • Built-in validation
  • TypeScript support
  • Easy integration with UI libraries
Tsx
import { useForm } from 'react-hook-form';import { FormFieldWrapper, Input, Button } from '@vendure/dashboard';interface FormData {    name: string;    email: string;}function MyForm() {    const form = useForm<FormData>();    const onSubmit = (data: FormData) => {        console.log(data);    };    return (        <form onSubmit={form.handleSubmit(onSubmit)}>            <FormFieldWrapper                control={form.control}                name="name"                label="Name"                render={({ field }) => <Input {...field} />}            />            <FormFieldWrapper                control={form.control}                name="email"                label="Email"                render={({ field }) => <Input type="email" {...field} />}            />            <Button type="submit">Submit</Button>        </form>    );}

GraphQL Integration: gql.tada

gql.tada provides type-safe GraphQL with:

  • Generated TypeScript types
  • IntelliSense for queries and mutations
  • Compile-time validation
  • Schema introspection
Tsx
import { graphql } from '@/gql';import { useMutation } from '@tanstack/react-query';const createProductMutation = graphql(`    mutation CreateProduct($input: CreateProductInput!) {        createProduct(input: $input) {            id            name            slug        }    }`);function CreateProductForm() {    const mutation = useMutation({        mutationFn: (input: CreateProductInput) => client.request(createProductMutation, { input }),    });    // TypeScript knows the exact shape of the input and response    const handleSubmit = (data: CreateProductInput) => {        mutation.mutate(data);    };    return (        // Form implementation        <div>Create Product Form</div>    );}

Notifications: Sonner

Sonner provides toast notifications with:

  • Beautiful animations
  • Customizable appearance
  • Promise-based notifications
  • Stacking support
Tsx
import { toast } from 'sonner';function MyComponent() {    const handleSave = async () => {        try {            await saveData();            toast.success('Data saved successfully!');        } catch (error) {            toast.error('Failed to save data', {                description: error.message,            });        }    };    // Promise-based toasts    const handleAsyncAction = () => {        toast.promise(performAsyncAction(), {            loading: 'Saving...',            success: 'Saved successfully!',            error: 'Failed to save',        });    };    return (        <div>            <button onClick={handleSave}>Save</button>            <button onClick={handleAsyncAction}>Async Save</button>        </div>    );}

Icons: Lucide React

Lucide React provides beautiful, customizable icons:

  • Consistent design
  • Tree-shakeable
  • Customizable size and color
  • Accessible by default
Tsx
import { ShoppingCartIcon, UserIcon, SettingsIcon } from 'lucide-react';function Navigation() {    return (        <nav className="flex space-x-4">            <a href="/products" className="flex items-center">                <ShoppingCartIcon className="mr-2 h-4 w-4" />                Products            </a>            <a href="/customers" className="flex items-center">                <UserIcon className="mr-2 h-4 w-4" />                Customers            </a>            <a href="/settings" className="flex items-center">                <SettingsIcon className="mr-2 h-4 w-4" />                Settings            </a>        </nav>    );}

Animations: Motion

Smooth animations powered by Motion (successor to Framer Motion):

  • High-performance animations
  • Declarative API
  • Spring-based animations
  • Layout animations
  • Gesture support
Tsx
import { motion } from 'motion/react';function AnimatedCard({ children }) {    return (        <motion.div            initial={{ opacity: 0, y: 20 }}            animate={{ opacity: 1, y: 0 }}            exit={{ opacity: 0, y: -20 }}            className="bg-white p-6 rounded-lg shadow"        >            {children}        </motion.div>    );}

Internationalization: Lingui

Lingui provides a powerful i18n solution for React:

  • ICU MessageFormat support
  • Automatic message extraction
  • TypeScript integration
  • Pluralization support
  • Compile-time optimization
Tsx
import { Trans, useLingui } from '@lingui/react/macro';function MyComponent() {    const { t } = useLingui();    return (        <div>            <h1>                <Trans>Welcome to Dashboard</Trans>            </h1>            <p>{t`Click here to continue`}</p>        </div>    );}
Was this chapter helpful?
Report Issue
Edited Feb 2, 2026·Edit this page