To integrate Magento with V0 by Vercel, generate a Next.js storefront UI with V0, create API routes that call the Magento REST API using an admin or customer access token, store your Magento base URL and credentials in Vercel environment variables, and deploy. Your app can display product catalogs, shopping carts, and order histories from a Magento or Adobe Commerce backend.
Build a Headless Magento Storefront with V0 and Next.js on Vercel
Magento powers over 250,000 e-commerce sites and is the dominant choice for enterprise B2B and large retail operations. Many businesses want the reliability of Magento as a backend combined with the performance and developer experience of a modern Next.js frontend — this is the headless commerce pattern. V0 can generate high-quality e-commerce UI components (product grids, filter sidebars, product detail pages, cart drawers, checkout flows) that you connect to your Magento backend via Next.js API routes.
Magento's REST API is comprehensive, covering the entire e-commerce lifecycle: product catalog management, category navigation, product search, shopping cart operations, customer accounts, order history, and checkout. The API supports both admin-level access (for fetching and managing catalog data) and customer-level access (for cart operations and order history tied to specific customer accounts). For a headless storefront, you typically use admin tokens server-side for catalog data and generate customer tokens server-side after customer authentication.
The Next.js and Magento combination is increasingly popular as the headless storefront pattern matures. Next.js's ISR (Incremental Static Regeneration) is ideal for product pages — you can statically generate product pages at build time and revalidate them periodically as Magento product data changes, combining the speed of static generation with the freshness of server-side rendering. V0 is particularly strong at generating the product listing page, product detail page, and shopping cart components that form the core of a headless storefront.
Integration method
Magento integrates with V0-generated Next.js apps through server-side API routes that call the Magento REST API or GraphQL API using admin tokens or customer tokens. Your Magento admin credentials and base URL are stored as server-only Vercel environment variables. The V0-generated storefront UI calls your Next.js routes, which proxy requests to your Magento instance and return structured product, cart, and order data for rendering.
Prerequisites
- A running Magento or Adobe Commerce instance — either self-hosted, Magento Cloud, or Adobe Commerce Cloud — with the REST API accessible from the internet
- Magento admin access to generate an Integration token — navigate to System → Integrations → Add New Integration, set required permissions, and note the Access Token provided
- Your Magento store base URL (e.g., https://your-magento-store.com) — the REST API is at {baseUrl}/rest/V1/
- A V0 account at v0.dev and a Vercel account for deploying the Next.js storefront
- Basic understanding of headless commerce — the Next.js frontend handles all rendering while Magento serves as the data API, with no Magento theme or frontend code deployed
Step-by-step guide
Generate the Storefront UI Components with V0
Generate the Storefront UI Components with V0
Open V0 at v0.dev and describe the e-commerce components you want to build. Magento data maps well to standard e-commerce patterns — product listings, category navigation, product detail pages, and cart management. The key advantage of V0 for headless Magento is that you can describe exactly the UX you want without being constrained by Magento's Luma theme or PWA Studio defaults. Be specific about product card layouts, filter sidebar behavior, variant selectors (size/color pickers for configurable products), and cart drawer animation. Magento product objects include fields like name, sku, price, special_price (sale price), media_gallery_entries (images), extension_attributes (stock status), and custom_attributes (any configurable attributes your store has defined). Describe these fields to V0 so it generates components with the right data bindings. For the product listing page, mention that you want ISR-compatible rendering — the page component fetches products server-side rather than client-side, which works with Next.js ISR for fast, cacheable responses. For the cart, describe a slide-in drawer pattern that persists cart state in localStorage (or a cookie) and syncs with Magento's cart API. After generating, push to GitHub via V0's Git panel and connect to Vercel.
Create a headless Magento product listing page component. The component receives a 'products' prop (array of product objects) and 'total' count. Render products in a responsive grid (4 columns desktop, 2 tablet, 1 mobile). Each product card: product image, product name, 'by {brandName}' subtitle, original price, sale price in red (if different), stock badge ('In Stock'/'Out of Stock'), star rating, and 'Add to Cart' button that calls addToCart(product.sku) prop function. Show a loading skeleton grid while products are undefined. Include a no-results empty state. Export as ProductGrid component.
Paste this in V0 chat
Pro tip: Ask V0 to generate a separate CartDrawer component that slides in from the right — this is the standard e-commerce cart pattern and V0 generates it well with Tailwind CSS animations and a semi-transparent overlay background.
Expected result: A ProductGrid component renders in V0's preview with product cards, sale price display, stock badges, and Add to Cart buttons. The component accepts a products array prop and handles loading and empty states.
Create the Magento Authentication and Product API Routes
Create the Magento Authentication and Product API Routes
Create the Next.js API routes that authenticate with Magento and fetch product catalog data. Magento's REST API uses bearer token authentication — for admin operations like fetching the full catalog, you use an Integration access token generated in the Magento admin. For customer-specific operations (cart, orders), you generate a customer token by calling the customer token endpoint with the customer's email and password credentials. For a headless storefront, the most common pattern is using the Integration token server-side for all catalog operations (since these are public data) and handling customer authentication separately through your Next.js auth layer. The Magento product search endpoint (GET /rest/V1/products) supports complex filtering using searchCriteria parameters — you can filter by category, price range, attribute values, and text search using a URL query string format that Magento parses into its search framework. Product responses include all configured attributes, images, pricing rules, and stock information. The response is paginated with total_count for building pagination controls. For configurable products (products with size/color variants), additional calls to /rest/V1/configurable-products/{sku}/options and /rest/V1/configurable-products/{sku}/children fetch the variant options and child product SKUs.
1// app/api/magento/products/route.ts2import { NextRequest, NextResponse } from 'next/server';34const MAGENTO_BASE_URL = process.env.MAGENTO_BASE_URL;5const MAGENTO_TOKEN = process.env.MAGENTO_INTEGRATION_TOKEN;67interface MagentoProduct {8 id: number;9 sku: string;10 name: string;11 price: number;12 status: number;13 type_id: string;14 media_gallery_entries?: Array<{ file: string; position: number; disabled: boolean }>;15 custom_attributes?: Array<{ attribute_code: string; value: string }>;16 extension_attributes?: { stock_item?: { qty: number; is_in_stock: boolean } };17}1819function getMagentoImageUrl(baseUrl: string, file: string) {20 return `${baseUrl}/pub/media/catalog/product${file}`;21}2223export async function GET(request: NextRequest) {24 if (!MAGENTO_BASE_URL || !MAGENTO_TOKEN) {25 return NextResponse.json(26 { error: 'Magento is not configured' },27 { status: 500 }28 );29 }3031 const { searchParams } = new URL(request.url);32 const page = parseInt(searchParams.get('page') ?? '1', 10);33 const pageSize = parseInt(searchParams.get('pageSize') ?? '20', 10);34 const categoryId = searchParams.get('categoryId') ?? '';35 const searchQuery = searchParams.get('q') ?? '';3637 // Build Magento searchCriteria query parameters38 const params = new URLSearchParams({39 'searchCriteria[currentPage]': page.toString(),40 'searchCriteria[pageSize]': pageSize.toString(),41 'searchCriteria[filter_groups][0][filters][0][field]': 'status',42 'searchCriteria[filter_groups][0][filters][0][value]': '1',43 'searchCriteria[filter_groups][0][filters][0][condition_type]': 'eq',44 fields:45 'items[id,sku,name,price,extension_attributes,media_gallery_entries,custom_attributes],total_count',46 });4748 if (categoryId) {49 params.set('searchCriteria[filter_groups][1][filters][0][field]', 'category_id');50 params.set('searchCriteria[filter_groups][1][filters][0][value]', categoryId);51 params.set('searchCriteria[filter_groups][1][filters][0][condition_type]', 'eq');52 }5354 if (searchQuery) {55 params.set('searchCriteria[filter_groups][2][filters][0][field]', 'name');56 params.set('searchCriteria[filter_groups][2][filters][0][value]', `%${searchQuery}%`);57 params.set('searchCriteria[filter_groups][2][filters][0][condition_type]', 'like');58 }5960 try {61 const response = await fetch(62 `${MAGENTO_BASE_URL}/rest/V1/products?${params.toString()}`,63 {64 headers: {65 Authorization: `Bearer ${MAGENTO_TOKEN}`,66 'Content-Type': 'application/json',67 },68 next: { revalidate: 300 }, // Cache for 5 minutes69 }70 );7172 if (!response.ok) {73 throw new Error(`Magento API error: ${response.status}`);74 }7576 const data = await response.json() as { items: MagentoProduct[]; total_count: number };7778 const products = (data.items ?? []).map((item) => {79 const salePrice = item.custom_attributes?.find(80 (a) => a.attribute_code === 'special_price'81 )?.value;8283 const image = item.media_gallery_entries?.find((e) => !e.disabled && e.position === 1);8485 return {86 id: item.id,87 sku: item.sku,88 name: item.name,89 price: item.price,90 salePrice: salePrice ? parseFloat(salePrice) : null,91 imageUrl: image ? getMagentoImageUrl(MAGENTO_BASE_URL!, image.file) : null,92 inStock: item.extension_attributes?.stock_item?.is_in_stock ?? true,93 stockQty: item.extension_attributes?.stock_item?.qty ?? 0,94 };95 });9697 return NextResponse.json({98 products,99 totalCount: data.total_count,100 page,101 pageSize,102 });103 } catch (error) {104 const message = error instanceof Error ? error.message : 'Unknown error';105 console.error('Magento API error:', message);106 return NextResponse.json(107 { error: 'Failed to fetch products', details: message },108 { status: 500 }109 );110 }111}Pro tip: Use the Magento 'fields' query parameter to request only the product fields your storefront needs — by default Magento returns all product attributes which can make responses very large. Specifying fields like 'items[id,sku,name,price,media_gallery_entries]' dramatically reduces payload size.
Expected result: GET /api/magento/products returns a normalized array of product objects with name, price, sale price, image URL, and stock status from your Magento catalog. Pagination and category filtering work via query parameters.
Implement Cart Operations with Magento Guest Cart API
Implement Cart Operations with Magento Guest Cart API
Create the cart API routes that handle add-to-cart, update quantity, and checkout operations. Magento supports two cart types: guest carts (for anonymous shoppers) and customer carts (for authenticated customers). For a public storefront, start with guest carts — the flow is to create a cart (POST /rest/V1/guest-carts which returns a cart ID token), then add items to the cart using that token (POST /rest/V1/guest-carts/{cartId}/items). Store the cart ID in a browser cookie or localStorage so it persists across page loads. The cart ID is not sensitive data, but treat it with reasonable care since anyone with the cart ID can access and modify that cart. For the cart display, GET /rest/V1/guest-carts/{cartId} returns the full cart with items, quantities, prices, and totals. For checkout, the Magento REST API supports a complete checkout flow including shipping address collection, shipping method estimation, payment information submission, and order placement. For most V0 storefront projects, a simplified flow that directs customers to the Magento checkout page (at your Magento store URL) after adding items to the cart is the fastest path to a working checkout — deep Next.js checkout integration with Magento requires implementing the full checkout API sequence which is complex to build and test correctly. The cart REST API also supports coupon code application (PUT /rest/V1/guest-carts/{cartId}/coupons/{couponCode}) for promotion codes.
Create a CartDrawer component that slides in from the right. It receives: isOpen (boolean), onClose (function), cartItems (array of {name, sku, price, quantity, imageUrl}), and cartTotal (number). Show cart items as a list with image thumbnail, product name, quantity control (+/-), item price, and a remove button. Show the cart subtotal at the bottom. Add a 'Proceed to Checkout' button and a 'Continue Shopping' link that closes the drawer. Show an empty cart message with a shopping bag icon when cartItems is empty. Add a semi-transparent dark overlay behind the drawer. Animate the drawer sliding in from the right using CSS transitions.
Paste this in V0 chat
Pro tip: For a simpler implementation, redirect customers to your Magento store's cart page (e.g., https://your-magento-store.com/checkout/cart) after adding items rather than building a full custom checkout. This lets V0 handle the product discovery UI while Magento handles the trusted checkout experience.
Expected result: The CartDrawer component slides in when items are added, showing product details, quantity controls, and the subtotal. The Proceed to Checkout button routes to the Magento checkout flow.
Configure Environment Variables and Deploy to Vercel
Configure Environment Variables and Deploy to Vercel
Push your code to GitHub and configure Magento credentials in Vercel. Open the Vercel Dashboard, select your project, and navigate to Settings → Environment Variables. Add MAGENTO_BASE_URL with your Magento store's base URL (without a trailing slash, e.g., https://your-magento-store.com), and MAGENTO_INTEGRATION_TOKEN with the Integration access token from Magento's admin panel (System → Integrations → your integration → Access Token). Neither variable should have the NEXT_PUBLIC_ prefix — Magento API calls should always be server-side to protect your integration token and avoid CORS issues. If you need the Magento URL accessible in client-side code (for image URLs), you can expose only the base URL as NEXT_PUBLIC_MAGENTO_BASE_URL since it's not sensitive. After adding environment variables for Production (and Preview if you want to test against a staging Magento instance), save and redeploy. Verify the deployment by opening your Vercel URL and checking that the product catalog loads from Magento. If you see CORS errors, confirm that all API calls are going through your Next.js API routes and not directly from the browser to Magento. Magento's REST API may need to have CORS configured if you're calling it from the client side, but the Next.js API route pattern avoids CORS entirely.
Pro tip: Test your Magento integration token by calling your Magento REST API directly in a browser: {MAGENTO_BASE_URL}/rest/V1/store/storeConfig with an Authorization: Bearer header. If you get a 200 response with store config data, your token and URL are correct.
Expected result: The Vercel deployment succeeds and the product catalog loads real products from your Magento backend with images, prices, stock status, and working Add to Cart functionality.
Common use cases
Headless Product Catalog
A Next.js product listing page that fetches the Magento catalog via API routes and renders products with filtering, sorting, and pagination. ISR keeps product data current without full page rebuilds on every request.
Create a product catalog page for an e-commerce store. Left sidebar has category filters (Electronics, Clothing, Accessories), price range slider, and brand checkbox filters. Main area shows products in a 4-column grid. Each product card has: product image placeholder, product name, brand name, price with a sale price crossed out if applicable, star rating with count, 'Add to Cart' button, and a wishlist heart icon. Top bar shows product count and sort dropdown (Price: Low to High, Newest, Best Sellers). Include pagination at the bottom. Use a clean modern e-commerce design.
Copy this prompt to try it in V0
Product Detail Page
A rich product detail page pulling Magento's full product data including images, attributes, configurable options (size/color), stock status, and related products. Customers can select variants and add to cart directly from the page.
Build a product detail page. Left side: large image with 4 thumbnail images below. Right side: product name (h1), SKU in gray, star rating row, price and sale price, a size selector with buttons (XS S M L XL), a color selector with colored circles, quantity input with +/- buttons, a large 'Add to Cart' button in blue, and an 'Add to Wishlist' link. Below the fold: a tabbed section with Product Description, Specifications (table), and Reviews. At the bottom: 'You Might Also Like' horizontal scroll of related product cards. Clean white design with bold typography.
Copy this prompt to try it in V0
Customer Order History Dashboard
An authenticated customer portal showing past Magento orders with status tracking, order details, and reorder functionality. Customers can view their complete purchase history and track shipments without navigating Magento's own account portal.
Design a customer account order history page. Header shows customer name and member-since date. Below: a list of orders sorted newest first. Each order row shows: order number, order date, total price, status badge (Processing/Shipped/Delivered in different colors), number of items, and 'View Details' and 'Reorder' buttons. Clicking 'View Details' expands an accordion showing individual line items with product names, quantities, and prices. Include a search bar to filter orders by order number. Use account dashboard styling with a left nav showing Account, Orders, Addresses, and Payment Methods.
Copy this prompt to try it in V0
Troubleshooting
Magento API returns 401 Unauthorized despite correct token
Cause: The Magento Integration token may have been regenerated, the integration may be inactive, or the token was created with insufficient API permissions. Token permissions in Magento are granular — the integration must have access to the specific API resources you're calling.
Solution: Log into Magento admin and navigate to System → Integrations. Find your integration and check that it's Active and that the Resource Access is set to 'All' or includes Products, Categories, and Cart endpoints. If the token was regenerated, update MAGENTO_INTEGRATION_TOKEN in Vercel. Trigger a redeployment after updating environment variables.
Product images return 404 or broken image errors
Cause: The Magento image URL is constructed incorrectly, the media base URL is different from the store base URL, or the Magento media files are served from a CDN with a different domain.
Solution: Fetch the media base URL from the Magento store config endpoint (GET /rest/V1/store/storeConfig) — the response includes a base_media_url field that is the correct URL prefix for product images. Use this value instead of constructing image URLs manually from your MAGENTO_BASE_URL.
1// Fetch actual media URL from Magento:2const config = await fetch(`${MAGENTO_BASE_URL}/rest/V1/store/storeConfig`, headers);3const { base_media_url } = await config.json();4const imageUrl = `${base_media_url}catalog/product${item.media_gallery_entries[0].file}`;searchCriteria filters return all products instead of filtering correctly
Cause: Magento's searchCriteria URL parameter format is complex and uses indexed arrays — incorrect indexing causes filters to be ignored silently rather than throwing errors.
Solution: Verify your searchCriteria URL parameters are correctly structured. The format uses bracketed notation: searchCriteria[filter_groups][0][filters][0][field]=status. Each filter group is ANDed together, filters within a group are ORed. Use a URL debugger to confirm the parameter string is correctly encoded before sending to Magento.
1// Correct searchCriteria structure for category filter:2params.set('searchCriteria[filter_groups][0][filters][0][field]', 'category_id');3params.set('searchCriteria[filter_groups][0][filters][0][value]', categoryId);4params.set('searchCriteria[filter_groups][0][filters][0][condition_type]', 'eq');Product prices show as 0 or undefined for configurable products
Cause: Configurable products in Magento have a price of 0 at the parent level — the actual prices live on the child simple products. The parent configurable product's price field is often 0 or the minimum child price.
Solution: For configurable products (type_id === 'configurable'), fetch the child products using GET /rest/V1/configurable-products/{sku}/children to get individual variant prices and SKUs. Display the price range (min to max child price) or the minimum price as the starting price.
1// Fetch children for configurable products:2if (item.type_id === 'configurable') {3 const children = await fetchMagento(`/rest/V1/configurable-products/${item.sku}/children`);4 const prices = children.map((c: {price: number}) => c.price).filter(Boolean);5 item.priceMin = Math.min(...prices);6 item.priceMax = Math.max(...prices);7}Best practices
- Use Magento's Integration token for server-side catalog reads — never expose this token in client-side code or prefix it with NEXT_PUBLIC_
- Use the Magento 'fields' query parameter to limit API response data to only the fields you need — this significantly reduces response size and improves performance
- Implement ISR (Incremental Static Regeneration) for product pages using Next.js generateStaticParams and revalidate — product data changes infrequently and static generation provides the best performance for product catalog pages
- Cache product API route responses with Next.js fetch revalidation (next: { revalidate: 300 }) to reduce Magento API load while keeping catalog data reasonably fresh
- Handle Magento's configurable products separately from simple products — configurable products have child SKUs with individual pricing and stock that must be fetched from the children endpoint
- Always route Magento API calls through Next.js API routes — calling Magento directly from the browser would require CORS configuration on Magento and expose your integration token
- For checkout, redirect to the native Magento checkout URL rather than building a custom checkout unless you need deep customization — Magento's checkout handles complex tax, shipping, and payment scenarios reliably
Alternatives
Use PrestaShop instead of Magento if you need a simpler, lighter open-source e-commerce platform for a small to mid-size store — PrestaShop has a simpler API and is easier to self-host than Magento's complex architecture.
Choose BigCommerce if you want a hosted SaaS alternative to Magento that offers similar enterprise features without the infrastructure overhead — BigCommerce has a strong headless commerce API and managed hosting.
Use WooCommerce instead of Magento if your business runs on WordPress and you need a simpler e-commerce solution — WooCommerce has a REST API similar to Magento's but with less complexity for small to medium catalogs.
Frequently asked questions
Should I use Magento's REST API or GraphQL API for a headless storefront?
For a new V0-generated headless storefront, Magento's GraphQL API is often better than REST — you can request exactly the fields you need in a single query, avoiding multiple REST calls and over-fetching. However, GraphQL support varies by Magento version and extension — Magento 2.4+ has good core GraphQL coverage, while older versions or heavily customized stores may have more complete REST coverage. This guide uses REST for compatibility, but you can use the same Next.js API route pattern with a POST to your Magento GraphQL endpoint instead.
What's the difference between a Magento Integration token and a customer token?
An Integration token is generated in the Magento admin panel and provides server-to-server access with the permissions you configure. It's used for admin-level operations like catalog reads. A customer token is generated by calling the /rest/V1/integration/customer/token endpoint with a customer's email and password — it provides access to that specific customer's account data (orders, cart, wishlist). Your Next.js app uses Integration tokens server-side for catalog data and generates customer tokens server-side during customer login for account-specific operations.
How do I handle Magento product images in a Next.js app?
Magento stores product images at {base_media_url}catalog/product{file_path}. Fetch the base_media_url from the Magento store config endpoint (GET /rest/V1/store/storeConfig) — don't assume it's the same as your store URL since many stores serve media from a CDN. Add your Magento image domain to the images.domains array in next.config.js to enable Next.js Image optimization for Magento product photos.
Can V0 generate a complete Magento storefront, or only individual components?
V0 can generate all the individual page components you need — product listing pages, product detail pages, category navigation, shopping cart, and account pages — but wiring them together into a complete routing structure and connecting them to the Magento API requires manual configuration. V0 excels at generating the UI layer; use this guide's API route patterns to connect those components to live Magento data.
Does Magento's API support product search with full-text search?
Yes — Magento's product search endpoint (GET /rest/V1/products/search or GET /rest/V1/products with searchCriteria) supports full-text search queries using Elasticsearch or OpenSearch as the search backend. Use the searchCriteria with name like '%query%' for simple name matching, or use the dedicated search endpoint for Elasticsearch-powered full-text search that covers product descriptions and attributes.
How do I keep product pages fast with ISR and Magento as the backend?
Configure Next.js generateStaticParams to pre-generate your most important product pages at build time using Magento's product list API. Set a revalidate interval (e.g., 300 seconds for 5 minutes) on your product detail pages so they automatically refresh from Magento periodically. For large catalogs, focus ISR on your top-traffic products and use on-demand revalidation (revalidatePath or revalidateTag) to refresh pages immediately when Magento sends a webhook notification of product changes.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation