Convert Figma logo to code with AI

saleor logostorefront

Saleor Storefront built using React, Next.js with App Router, TypeScript, GraphQL, and Tailwind CSS.

1,429
822
1,429
37

Top Related Projects

14,142

Next.js Commerce

35,098

The world's most flexible commerce platform.

Shopware 6 is an open commerce platform based on Symfony Framework and Vue and supported by a worldwide community and more than 3.100 community extensions

A customizable, open-source ecommerce platform built on WordPress. Build any commerce solution you can imagine.

Quick Overview

Saleor Storefront is an open-source e-commerce frontend built with React and Next.js. It's designed to work seamlessly with the Saleor GraphQL API, providing a modern, customizable, and performant shopping experience for customers.

Pros

  • Built with modern technologies (React, Next.js, TypeScript)
  • Highly customizable and extendable
  • Optimized for performance and SEO
  • Integrates seamlessly with Saleor's GraphQL API

Cons

  • Steep learning curve for developers unfamiliar with React and GraphQL
  • Requires separate backend setup (Saleor Core)
  • Limited out-of-the-box design customization options
  • May require additional development effort for complex e-commerce features

Getting Started

To set up Saleor Storefront locally:

  1. Clone the repository:

    git clone https://github.com/saleor/storefront.git
    cd storefront
    
  2. Install dependencies:

    pnpm install
    
  3. Set up environment variables:

    cp .env.example .env.local
    

    Edit .env.local to include your Saleor API URL.

  4. Run the development server:

    pnpm dev
    
  5. Open http://localhost:3000 in your browser to see the storefront.

Competitor Comparisons

14,142

Next.js Commerce

Pros of Commerce

  • More flexible e-commerce framework, supporting multiple providers (Shopify, BigCommerce, Swell, etc.)
  • Extensive documentation and examples for various use cases
  • Optimized for performance with Next.js and Vercel deployment

Cons of Commerce

  • Steeper learning curve due to its flexibility and multiple integrations
  • Less opinionated structure, which may require more setup and configuration
  • Smaller community compared to Saleor ecosystem

Code Comparison

Commerce:

const { products } = await commerce.getAllProducts({
  variables: { first: 4 },
})

Storefront:

const { data } = await apolloClient.query({
  query: ProductListDocument,
  variables: { first: 4 },
})

Both repositories use GraphQL for data fetching, but Commerce offers a more abstracted API layer, while Storefront relies directly on Apollo Client for querying.

Commerce provides a unified interface for multiple e-commerce backends, making it more versatile for different projects. Storefront, being tailored specifically for Saleor, offers a more streamlined experience for developers working within the Saleor ecosystem.

Ultimately, the choice between these repositories depends on project requirements, existing infrastructure, and developer preferences.

35,098

The world's most flexible commerce platform.

Pros of Medusa

  • More flexible and customizable backend architecture
  • Better support for headless commerce setups
  • Stronger focus on developer experience and extensibility

Cons of Medusa

  • Smaller community and ecosystem compared to Saleor
  • Less mature admin dashboard and frontend components
  • Steeper learning curve for non-technical users

Code Comparison

Medusa (Node.js):

const product = await productService.create({
  title: "T-Shirt",
  variants: [
    { title: "Small", prices: [{ amount: 1000, currency_code: "usd" }] },
    { title: "Medium", prices: [{ amount: 1200, currency_code: "usd" }] }
  ]
});

Saleor (Python):

product = Product.objects.create(
    name="T-Shirt",
    product_type=product_type,
    category=category,
)
ProductVariant.objects.bulk_create([
    ProductVariant(product=product, name="Small", price_amount=10.00),
    ProductVariant(product=product, name="Medium", price_amount=12.00)
])

Both repositories offer robust e-commerce solutions, but Medusa focuses more on backend flexibility and headless commerce, while Saleor provides a more comprehensive full-stack solution with a polished storefront. Medusa's code tends to be more modular and event-driven, while Saleor's approach is more traditional and Django-centric.

Shopware 6 is an open commerce platform based on Symfony Framework and Vue and supported by a worldwide community and more than 3.100 community extensions

Pros of Shopware

  • More comprehensive e-commerce solution with built-in CMS and ERP features
  • Larger community and ecosystem with extensive plugin marketplace
  • Supports both B2C and B2B scenarios out of the box

Cons of Shopware

  • Steeper learning curve due to its complexity and extensive feature set
  • Heavier codebase, potentially impacting performance for smaller projects
  • Less flexibility for custom frontend implementations compared to Storefront

Code Comparison

Storefront (React):

const ProductCard = ({ product }) => (
  <div className="product-card">
    <img src={product.image} alt={product.name} />
    <h3>{product.name}</h3>
    <p>{product.price}</p>
  </div>
);

Shopware (Twig):

{% block component_product_box %}
    <div class="product-box">
        {% block component_product_box_image %}
            {% sw_thumbnails 'product-image-thumbnails' with {
                media: product.cover.media
            } %}
        {% endblock %}
        <h3>{{ product.name }}</h3>
        <p>{{ product.calculatedPrice.unitPrice|currency }}</p>
    </div>
{% endblock %}

The code comparison shows that Storefront uses React for its frontend, allowing for more dynamic and interactive components. Shopware, on the other hand, uses Twig templating, which is more traditional and may be easier for developers familiar with PHP-based systems.

A customizable, open-source ecommerce platform built on WordPress. Build any commerce solution you can imagine.

Pros of WooCommerce

  • Larger community and ecosystem with extensive plugin support
  • Seamless integration with WordPress, leveraging its content management capabilities
  • More comprehensive out-of-the-box features for various e-commerce scenarios

Cons of WooCommerce

  • Heavier codebase, potentially impacting performance for larger stores
  • Less flexibility in terms of headless architecture and modern frontend technologies
  • Steeper learning curve for developers not familiar with WordPress ecosystem

Code Comparison

WooCommerce (PHP):

add_action( 'woocommerce_before_main_content', 'woocommerce_output_content_wrapper', 10 );
add_action( 'woocommerce_after_main_content', 'woocommerce_output_content_wrapper_end', 10 );

Saleor Storefront (React):

import { ApolloProvider } from "@apollo/client";
import { BrowserRouter as Router, Route } from "react-router-dom";
import { ProductsList } from "./components/ProductsList";

Summary

WooCommerce offers a robust, WordPress-integrated solution with a vast ecosystem, while Saleor Storefront provides a modern, headless approach with React. WooCommerce excels in traditional setups, whereas Saleor Storefront is more suitable for developers seeking a flexible, API-first architecture. The choice depends on specific project requirements, existing infrastructure, and development team expertise.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Deploy with Vercel

saleor-storefront-paper-fin

apple-touch-icon-dark

Paper

A minimal, production-ready storefront template for Saleor.
Clean as a blank page — built to ship with agents and humans.



[!TIP] Questions or issues? Check our Discord for help.


Why Paper?

Ship faster, customize everything. Paper is a new release—expect some rough edges—but every component is built with real-world e-commerce in mind. This is a foundation you can actually build on.

🛒 Open Checkout (v2)

The checkout is where most storefronts fall apart or fall short. Paper's doesn't — and checkout v2 aligns it with the rest of the stack: App Router, Server Components, server actions, and the same BFF session as the storefront (no client-side urql or browser Saleor tokens).

Storefront cart                    Checkout surface
─────────────                      ────────────────
src/lib/checkout.ts                src/app/(checkout)/checkout/
  cookie + mutations        →        CheckoutSessionLoader (RSC)
@paper/session-bridge                  CheckoutApp → steps + payment
buildCheckoutPath()                  /checkout/complete?order= (confirmation)
  • Server-first cart — RSC loads checkout + me on entry; client context is a cache of server truth (CheckoutDataProvider).
  • URL-driven steps — ?step=contact|shipping|payment updates shallowly (no full page refetch per click); browser Back walks the funnel.
  • Dedicated confirmation — /checkout/complete?order= is separate from the active cart route.
  • Extensible payments — Registry (INTEGRATED_GATEWAYS) with Stripe + Dummy; add gateways via checkout-payment-gateways skill.
  • Shared BFF auth — Sign-in via /api/auth/login; session resolved server-side (resolveSessionUser — guest / authenticated / unavailable).
  • Multi-step, mobile-first — Focused forms, international address fields, composable step components.

Developer docs: start at skills/saleor-paper-storefront/rules/paper-surfaces.md, then checkout-management.md. Forks on the old urql checkout: migrations/atomic/2026-06-checkout-v2/.

🌍 International by Default

One codebase, many markets. Browse URLs are /{locale}/{channel}/… — e.g. /en/us/products/hoodie (English, US market, USD) and /fr/fr/products/hoodie (French, France, EUR) — with legacy /{channel}/… paths redirecting automatically. Each locale gets its own cached catalog payload, translated product copy from Saleor, per-channel pricing and currency, and hreflang/canonical metadata.

  • Region picker — header control switches locale and channel together (language + market + currency)
  • Three string systems — Saleor catalog translations, merchant-editable storefront content (CMS), and code-owned UI via next-intl (messages/{locale}.json)
  • Six built-in locales — en, pl, de, fr, fi, nb (extend via LOCALE_DEFINITIONS in src/config/locale.ts)

Storefront channels are explicit. Saleor may have many channels (B2B, wholesale, internal regions); Paper only exposes the slugs you configure via STOREFRONT_CHANNELS. Disallowed channel URLs return 404. For a single-channel store, set NEXT_PUBLIC_DEFAULT_CHANNEL only—the footer channel selector is hidden automatically.

Developer docs: docs/international-storefront.md · ADRs 0001 / 0002 · skills ui-locale-routing / ui-i18n

📱 Product Pages Done Right

The hard parts are solved. Adapt the look, keep the logic.

  • Partial Prerendering (PPR) — Product name, attributes, and SEO stay in a static cached shell; variant gallery and add-to-cart stream in via Suspense when searchParams change.
  • Multi-attribute variant selection — Color + Size + Material? Handled. Complex variant matrices just work.
  • Dynamic pricing — Sale prices, variant-specific pricing, channel pricing—all reactive.
  • Image gallery — Next.js Image optimization, proper aspect ratios, keyboard navigation.

♿ Accessibility Built In

Not an afterthought. Focus management on step transitions, keyboard navigation everywhere, semantic HTML, proper ARIA labels. Everyone deserves to shop.

🤖 AI-Ready Codebase

Built for front-end developers and AI agents. The codebase includes:

  • AGENTS.md — Architecture overview and quick reference for AI assistants
  • skills/saleor-paper-storefront/ — 21 task-specific rules covering GraphQL, caching, i18n, variant selection, checkout v2, and more
  • saleor/agent-skills — Universal Saleor API patterns; external skills via pnpm skills:bootstrap (skills-lock.json)
  • Consistent patterns — Predictable structure that AI tools can navigate and modify confidently

Whether you're pair-programming with Cursor, Claude, or Copilot—the codebase is designed to help them help you.

⚡ Bleeding Edge Stack

  • Next.js 16 with App Router and Server Components
  • React 19 with the latest concurrent features
  • TypeScript in strict mode—your IDE will thank you
  • Tailwind CSS with design tokens (OKLCH colors, CSS variables)
  • GraphQL Codegen for type-safe Saleor API calls

What's in the Box

FeatureDescription
Checkout (v2)RSC + server actions, shallow step URLs, payment registry (Stripe/Dummy), /checkout/complete
CartSlide-over drawer with real-time updates, quantity editing
Product PagesMulti-attribute variants, image gallery, sticky add-to-cart
Product ListingsCategory & collection pages with PPR (cached hero + dynamic filters), pagination
International/{locale}/{channel}/ routing, region picker, Saleor translations, next-intl UI, hreflang SEO
Storefront contentMerchant-editable copy layer (code or Saleor Models) — homepage, cart trust, checkout editorial
NavigationDynamic menus from Saleor, mobile hamburger, breadcrumbs
SEOPer-locale metadata, JSON-LD, Open Graph images, hreflang alternates
CachingCache Components (PPR), named cacheLife tiers, per-locale catalog cache, webhooks
Saleor Cloud Paper appSaleor Cloud only — Dashboard extension for cache invalidation webhooks and Preview in storefront
Customer ProfileAccount dashboard, address book, order history, password change, account deletion
AuthenticationLogin, register, password reset, guest checkout
API ResilienceAutomatic retries, rate limiting, timeouts—handles flaky connections gracefully

Caching Architecture

Paper uses Cache Components (Next.js 16 — "use cache", cacheLife, cacheTag behind cacheComponents: true) for optimal performance: static shells load instantly while dynamic content streams in. Learn more in the directive docs or see skills/saleor-paper-storefront/rules/data-caching.md for project-specific patterns.

The display-cached, checkout-live model ensures fast browsing with accurate checkout:

┌─────────────────────────────────────────────────────────────────────┐
│                         DATA FRESHNESS                              │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│   Product Pages          Cart / Checkout         Payment            │
│   ──────────────         ──────────────          ───────            │
│                                                                     │
│   ┌───────────┐         ┌───────────┐          ┌───────────┐       │
│   │  CACHED   │────────▶│   LIVE    │─────────▶│   LIVE    │       │
│   │  5 min    │  Add    │  Always   │   Pay    │  Always   │       │
│   └───────────┘  to     └───────────┘          └───────────┘       │
│                  Cart                                               │
│   Fast page loads        Real-time prices       Saleor validates    │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

How It Works

ComponentFreshnessWhy
Product pagesCached (catalog)Static shell + dynamic variant islands (PPR)
Category/CollectionCached (catalog)Cached hero from params; filters/pagination stream in Suspense
Homepage featuredCached (catalog)Sync page shell; product grid streams in nested Suspense
Navigation / footerCached (menus)Per-channel tags; per-locale menu payloads in cache keys
Storefront contentCached (menus)Tag storefront-content:{channel}:{locale}
Cart drawerAlways liveSaleor API with cache: "no-cache"
CheckoutAlways liveRSC entry + server actions (cache: "no-cache"), real-time totals

cacheLife tiers (see src/lib/cache-life-profiles.ts):

ProfileFallback TTLUsed for
catalog~5 minProducts, categories, collections, homepage
menus~1 hrHeader nav, footer menu
channels~1 dayFooter channel metadata

Webhook revalidateTag(tag, profile) clears data immediately; TTL is the safety net when webhooks are missing.

Locale

Browse URLs are /{locale}/{channel}/…. Cached catalog fetches pass localeSlug — separate cache entry per language, same warm-path speed. Invalidation uses slug-scoped tags (product:{slug}) and revalidates every locale path via buildPathsForAllLocales(). GraphQL uses Saleor base language codes (PL, not PL_PL). See data-caching.md § Locale & Caching.

PPR page patterns

Cached GraphQL lives in src/lib/catalog/, src/lib/menus/, and src/lib/channels/ — not in layout or page components. Pages are thin orchestrators with nested <Suspense> for dynamic islands.

PDP — params only in the static shell; gallery and variant selection read searchParams:

ProductPage (sync)
└── ProductShell → getProductData(slug, channel, locale) "use cache"
    ├── h1, attributes, JSON-LD, LCP preload
    ├── Suspense → VariantGalleryDynamic (searchParams)
    └── Suspense → VariantSectionDynamic (searchParams)

PLP (category, collection, all products) — cached hero/metadata from params; filter/sort/pagination in a dynamic grid:

Page
├── CategoryHero ← getCategoryData "use cache"
└── Suspense → CategoryProducts (searchParams, always fresh fetch)

Homepage — sync <section> shell; featured collection grid in nested Suspense.

Loading UX — route-level loading.tsx files (products, categories, collections) show skeletons during navigation. The main layout does not wrap {children} in Suspense fallback={null}.

Cache tags (see src/lib/cache-manifest.ts):

Tag patternInvalidated when
product:{slug}Product updated (all locales)
category:{slug}Category updated (all locales)
collection:{slug}Collection updated (all locales)
page:{slug}CMS page updated (all locales)
navigation:{channel}Main menu changed for channel
footer-menu:{channel}Footer menu changed for channel
storefront-content:{channel}:{locale}Storefront Models page updated
channelsChannel list metadata

Featured homepage products use tag collection:featured-products (same catalog profile as collections).

Instant Updates with Webhooks

Saleor Cloud (recommended): Install the Saleor Cloud Paper app from Dashboard → Extensions. Available on Saleor Cloud only for now. It registers revalidation webhooks for products, categories, collections, pages, menus, and promotions; discovers cache tags via /api/cache-info; and adds Preview in storefront on product pages in Dashboard.

Self-hosted / manual setup:

  1. Create webhooks in Saleor Dashboard → Configuration → Webhooks
  2. Point to https://your-store.com/api/revalidate
  3. Subscribe to product/category/collection/page events; for menus use MENU_* / MENU_ITEM_* and include { menu: { slug } } for navbar and footer menus
  4. Set SALEOR_WEBHOOK_SECRET env var

Manual revalidation (requires REVALIDATE_SECRET):

# Single product (all locale cache entries for slug)
curl "https://your-store.com/api/revalidate?secret=xxx&tag=product:blue-hoodie"

# Single product path (one locale; tag still clears all locales)
curl "https://your-store.com/api/revalidate?secret=xxx&tag=product:blue-hoodie&path=/pl/default-channel/products/blue-hoodie"

# CMS page (tag only — invalidates getPageData across channels)
curl "https://your-store.com/api/revalidate?secret=xxx&tag=page:about-us"

# Navigation for one channel (tag or tag + channel query)
curl "https://your-store.com/api/revalidate?secret=xxx&tag=navigation:us"
curl "https://your-store.com/api/revalidate?secret=xxx&tag=navigation&channel=us"

# All tags for every storefront channel
curl "https://your-store.com/api/revalidate?secret=xxx&all=1"

Without webhooks? TTL handles it—cached data expires per the catalog / menus / channels profiles above.

Why This Is Safe

  • Saleor is the source of truth: checkoutLinesAdd calculates prices server-side
  • Cart always fetches fresh: Users see current prices before checkout
  • Payment validates: checkoutComplete uses real-time data

📚 Deep dive: See skills/saleor-paper-storefront/rules/data-caching.md for the full architecture, Cache Components (PPR), webhook setup, and debugging guide.


Quick Start

[!NOTE] New to Saleor? Check out saleor.io/start to learn how storefronts work underneath.

1. Get a Saleor Backend

Option A: Free Saleor Cloud account (recommended)

Option B: Run locally with Docker

2. Clone & Configure

# Using Saleor CLI (recommended)
npm i -g @saleor/cli@latest
saleor storefront create --url https://{YOUR_INSTANCE}/graphql/

# Or manually
git clone https://github.com/saleor/storefront.git
cd storefront
cp .env.example .env
pnpm install

# Optional — wire agent skills for Cursor (see "For AI Agents" below)
pnpm skills:bootstrap

Edit .env with your Saleor instance details:

NEXT_PUBLIC_SALEOR_API_URL=https://your-instance.saleor.cloud/graphql/
NEXT_PUBLIC_DEFAULT_CHANNEL=default-channel  # Your Saleor channel slug

Multi-channel (recommended — explicit allowlist):

STOREFRONT_CHANNELS=us,uk,eu
NEXT_PUBLIC_DEFAULT_CHANNEL=us
NEXT_PUBLIC_STOREFRONT_LOCALES=en,pl,de,fr,fi,nb  # URL locale slugs
SALEOR_APP_TOKEN=...  # Server-side only — footer currency selector metadata

Finding your channel slug: In Saleor Dashboard → Configuration → Channels → copy the slug

Note: SALEOR_APP_TOKEN alone no longer auto-discovers every Saleor channel. Set STOREFRONT_CHANNELS or opt in with STOREFRONT_DISCOVER_CHANNELS=true (see Environment Variables).

3. Run

pnpm dev

Open localhost:3000. That's it.


Development

Commands

pnpm dev                    # Start dev server
pnpm build                  # Production build
pnpm run generate           # Regenerate GraphQL types (storefront)
pnpm run generate:checkout  # Regenerate GraphQL types (checkout)

Project Structure

src/
├── app/                    # Next.js App Router
│   ├── (storefront)/[locale]/[channel]/  # Browse, cart, account
│   └── (checkout)/checkout/              # Checkout route (/checkout)
├── messages/               # next-intl UI strings (per locale)
├── session-bridge/         # @paper/session-bridge — storefront ↔ checkout handoff
├── checkout/               # Checkout UI, providers, payment registry (GraphQL via server actions)
├── graphql/                # GraphQL queries
├── gql/                    # Generated types (don't edit)
├── lib/                    # Server utilities & cached data layer
│   ├── catalog/            # getCategoryData, getCollectionData, getFeaturedProducts
│   ├── menus/              # getNavbarMenuItems, getFooterMenuItems
│   ├── channels/           # getCachedChannelsList
│   ├── cache-manifest.ts   # Tag registry + cacheLife mapping
│   └── cache-life-profiles.ts
├── ui/components/          # UI components
│   ├── account/            # Customer profile & address book
│   ├── pdp/                # Product detail page
│   ├── plp/                # Product listing page
│   ├── cart/               # Cart drawer
│   └── ui/                 # Primitives (Button, Badge, etc.)
└── styles/brand.css        # Design tokens

For AI Agents

If you're working with AI coding assistants, point them to:

  • AGENTS.md — Architecture, commands, gotchas
  • skills/saleor-paper-storefront/ — 21 project-specific rules (GraphQL, caching, i18n, checkout, etc.)
  • skills/saleor-paper-storefront/references/code-conventions.md — File naming, exports, imports
  • saleor/agent-skills — Universal Saleor patterns and optional community skills

After clone, wire skills for Cursor discovery (repo-root skills/ is not scanned automatically):

pnpm skills:bootstrap

Symlinks the project skill into .agents/skills/, then runs npx skills experimental_install from skills-lock.json. Do not run npx skills add . --skill saleor-paper-storefront — it copies a drifting snapshot.

Environment Variables

# Required
NEXT_PUBLIC_SALEOR_API_URL=https://your-instance.saleor.cloud/graphql/
NEXT_PUBLIC_DEFAULT_CHANNEL=default-channel  # Fallback channel; root "/" redirects here

# Multi-channel (recommended)
STOREFRONT_CHANNELS=us,uk,eu               # Comma-separated allowlist — routes, revalidation, footer

# Optional
NEXT_PUBLIC_STOREFRONT_URL=                  # Canonical URLs and OG images
NEXT_PUBLIC_DEFAULT_LOCALE=en                # Default URL locale slug
NEXT_PUBLIC_STOREFRONT_LOCALES=en,pl,de,fr,fi,nb  # Enabled locale slugs
REVALIDATE_SECRET=                           # Manual cache invalidation (GET /api/revalidate)
SALEOR_WEBHOOK_SECRET=                       # Webhook HMAC verification
SALEOR_APP_TOKEN=                            # Server-side: footer channel metadata (never exposed to client)
STOREFRONT_DISCOVER_CHANNELS=true            # Opt-in: discover ALL active Saleor channels from API
                                             # (not recommended when Saleor has many channels; prefer STOREFRONT_CHANNELS)

Channel resolution order (getStorefrontChannelSlugs):

  1. STOREFRONT_CHANNELS — explicit allowlist (recommended)
  2. STOREFRONT_DISCOVER_CHANNELS=true + SALEOR_APP_TOKEN — all active channels from API
  3. NEXT_PUBLIC_DEFAULT_CHANNEL only — single-channel storefront

Payments

The checkout architecture supports Saleor payment apps like Adyen and Stripe. The heavy lifting is done—integrating your gateway requires minimal work compared to building from scratch.

How payment config is split

Paper deliberately keeps secrets out of the storefront. Stripe keys are never set in the storefront .env:

WhereWhat lives there
Saleor Stripe app (Dashboard)Stripe secret key + publishable key + webhook signing secret
Storefront .envFeature flags only (NEXT_PUBLIC_ENABLE_STRIPE_PAYMENTS, …) — no keys
RuntimeThe storefront receives the publishable key from Saleor's paymentGatewayInitialize

So "set up Stripe" means: configure the Saleor Stripe app with your keys, then flip the feature flags in the storefront.

Set up Stripe with sandbox (test) keys

You need a Stripe account in Test mode and the Saleor Stripe app installed on your Saleor instance.

  1. Grab your Stripe test keys. In the Stripe Dashboard, toggle Test mode (top-right) and copy:

    • Publishable key — pk_test_…

    • Secret key — sk_test_…

    Test mode is Stripe's sandbox: no real charges, and you pay with test cards (e.g. 4242 4242 4242 4242, any future expiry, any CVC).

  2. Install & configure the Saleor Stripe app. In Saleor Dashboard → Apps (or Extensions), install the Stripe payment app and open its configuration. Paste the test publishable and secret keys. The app registers the Stripe webhook for you; assign the configuration to the channel(s) you're testing.

  3. Enable Stripe in the storefront. Add to .env (or .env.local):

    NEXT_PUBLIC_ENABLE_STRIPE_PAYMENTS=true
    ENABLE_STRIPE_PAYMENTS=true   # server-side mirror for the transaction guard
    
    # Optional — wallet buttons (Apple Pay / Google Pay / Link); on by default when Stripe is enabled
    # NEXT_PUBLIC_ENABLE_STRIPE_EXPRESS_CHECKOUT=false
    

    In local development (NODE_ENV === development) Stripe auto-enables, so these flags are mainly for cloud/staging builds. Publishable keys still come from Saleor at runtime — never put pk_… / sk_… in the storefront env.

  4. Run a test order. pnpm dev, add a product, go to checkout, and pay with a Stripe test card. Use 4000 0027 6000 3184 to exercise the 3DS redirect flow.

Test without Stripe (Dummy Payment)

To validate the full checkout flow without any Stripe setup, use the Dummy Payment app (auto-enabled in development):

ALLOW_DUMMY_PAYMENT=true
NEXT_PUBLIC_ALLOW_DUMMY_PAYMENT=true

Developer docs: payment registry, submit patterns, and adding a gateway → skills/saleor-paper-storefront/rules/checkout-payment-gateways.md. All payment env vars are listed in .env.example.


Customization

Paper works as a reference implementation and as a starting point for your own storefront. Start here:

  • Colors & typography → src/styles/brand.css
  • Components → src/ui/components/
  • Checkout flow → src/checkout/views/saleor-checkout/

The design token system uses CSS custom properties—swap the entire color palette by editing a few lines.


Next Steps

Known gaps and planned improvements:

  • Checkout functional i18n — checkout step labels still live in storefront content (ADR 0002); migrate to next-intl
  • Filtering logic iteration — fetching attributes from API for dynamic product filters
  • Error / not-found pages — localized shells for global error boundaries

License

FSL-1.1-ALv2 (Functional Source License, Version 1.1, ALv2 Future License) — use it, modify it, ship it. Build your storefront, run your business. The license converts to Apache 2.0 after two years.

Want to offer it as a managed service? Let's talk.



Built with 🖤 by the Saleor team