Express CSV Logo

Quickstart

Use this pre-built prompt to get started faster with Next.js.

Alternatively, follow these steps to manually add ExpressCSV to a Next.js app and receive imports in a Route Handler.

  1. Install the React SDK

    npm install @expresscsv/react
  2. Get your publishable key

    You need a publishable key from the dashboard to connect the importer.

    New accounts start with two environments: Production and Development. For this example, grab the key from your Development environment.

  3. Create a client component for the importer

    If you use the App Router, put the importer button in a client component:

    'use client';
    
    import { useExpressCSV, x } from '@expresscsv/react';
    
    const productSchema = x.row({
      sku: x.string().label('SKU'),
      name: x.string().min(1).label('Product Name'),
      price: x.number().min(0).currency('USD').label('Price'),
    });
    
    export function ImportProductsButton() {
      const { open, isOpen } = useExpressCSV({
        schema: productSchema,
        publishableKey: 'pk_test_...',
        importIdentifier: 'product-import',
        title: 'Import products',
      });
    
      return (
        <button
          type="button"
          disabled={isOpen}
          onClick={() =>
            open({
              chunkSize: 500,
              webhook: {
                url: '/api/webhooks/products-import',
                headers: {
                  Authorization: 'Bearer your-api-token',
                },
                metadata: {
                  userId: 'user-123',
                },
              },
            })
          }
        >
          Import Products
        </button>
      );
    }
  4. Render the button from a page

    import { ImportProductsButton } from './ImportProductsButton';
    
    export default function Page() {
      return <ImportProductsButton />;
    }

    If you still use the Pages Router, the same client component can be rendered from a page in pages/ with no extra setup.

  5. Receive webhook deliveries in a Route Handler

    Keep the schema in a shared or core package so both the client and the Route Handler can import it, then use @expresscsv/schemas to infer the webhook payload:

    import { NextResponse } from 'next/server';
    import type { InferWebhookPayload } from '@expresscsv/schemas';
    import { productSchema } from '@/core/product-schema';
    
    export async function POST(request: Request) {
      const token = request.headers.get('authorization');
    
      if (token !== 'Bearer your-api-token') {
        return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
      }
    
      const payload =
        (await request.json()) as InferWebhookPayload<typeof productSchema>;
    
      console.log('Received import chunk', payload.records);
    
      return NextResponse.json({ ok: true });
    }

    Return a 2xx response for each chunk. 5xx and 429 responses are retried automatically, while other 4xx responses are treated as permanent failures.

  6. Optional: disable preloading

    By default, the widget preloads in a hidden iframe so it opens instantly. To show a loading screen instead:

    const { open } = useExpressCSV({
      schema,
      publishableKey: 'pk_test_...',
      importIdentifier: 'user-import',
      preload: false,
    });

What's Next

  • Types — define field types, validation rules, and inferred types
  • Styling — theme the widget to match your app
  • Webhooks — deliver records to your backend
  • API Reference — full option and return value reference