# Build a storefront page with the SDK

> A Next.js product list and product page, server-rendered, in a few files.

Source: https://docs.dashfordevs.com/v1/getting-started/storefront-with-the-sdk · Topic: Quickstart · Updated: 2026-11-07

## 1\. Install

The SDK is installed from GitHub (ask us for access to the repository):

```bash
npm install github:CodeCraft-Studios-LLC/dashfordevs-sdk#v0.3.3
```

## 2\. Environment

```bash
# .env.local
NEXT_PUBLIC_DEVDASH_PUBLIC_KEY=pk_test_YOUR_PUBLIC_KEY
DEVDASH_SECRET_KEY=sk_test_YOUR_SECRET_KEY
```

Only variables starting with `NEXT_PUBLIC_` reach the browser. The secret key must never be one of them; the SDK refuses to start if it finds an `sk_` key in a `NEXT_PUBLIC_` variable.

## 3\. Two clients: server and browser

```ts
// lib/dash.server.ts: import only from server components and route handlers
import "server-only";
import { DashClient } from "dash4devs";
import { assertServerOnlyKey } from "dash4devs/security";

assertServerOnlyKey(process.env.DEVDASH_SECRET_KEY);
export const dash = new DashClient({ apiKey: process.env.DEVDASH_SECRET_KEY! });
```

```ts
// lib/dash.client.ts: safe in the browser
import { DashClient } from "dash4devs";
export const dash = new DashClient({ apiKey: process.env.NEXT_PUBLIC_DEVDASH_PUBLIC_KEY! });
```

## 4\. A product list

```tsx
// app/shop/page.tsx
import Link from "next/link";
import { dash } from "@/lib/dash.server";

export default async function Shop() {
  const { products } = await dash.products.list({ limit: 24, include: ["main_size"] });
  return (
    <ul>
      {products.map((p) => (
        <li key={p.id}><Link href={`/shop/${p.slug}`}>{p.name}</Link></li>
      ))}
    </ul>
  );
}
```

## 5\. A product page

```tsx
// app/shop/[slug]/page.tsx
import { notFound } from "next/navigation";
import { DashApiError } from "dash4devs";
import { DashImage } from "dash4devs/react";
import { dash } from "@/lib/dash.server";

export default async function Product({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = await params;
  try {
    const { product } = await dash.products.getCore(slug);
    return (
      <article>
        <h1>{product.name}</h1>
        {product.main_image && <DashImage src={product.main_image} alt={product.name} width={800} />}
      </article>
    );
  } catch (e) {
    if (e instanceof DashApiError && e.status === 404) notFound();
    throw e;
  }
}
```

`DashImage` picks the right size from our CDN for each screen.

## 6\. Ship it

New to the App Router? The [Next.js documentation](https://nextjs.org/docs/app) covers server components and data fetching in depth.

Deploy anywhere that runs Next.js, or on [DashForDevs Cloud](https://docs.dashfordevs.com/v1/cloud) straight from GitHub. Before you go live, switch to **live** keys and add your domain under **Developers → Allowed origins**.

Next: [How the platform works](https://docs.dashfordevs.com/v1/how-it-works).
