One of the greatest benefits of composable, headless commerce is the flexibility it introduces to the developer experience of building shopping experiences. Decoupling website content and commerce data makes it easier for content and commerce teams of experts to work independently and more efficiently. With Commerce Layer, content managers can work with a best-of-breed headless CMS like Sanity, merchants can build their inventory in Commerce Layer, and developers can build with any stack in their most preferred programming language while utilizing Commerce Layer’s APIs.
In this tutorial, you will learn how we built the Commerce Layer Starter with Nextjs, Sanity studio, and deployed it to Netlify. At the end of the tutorial, you should be able to set up and build your own 1-click sanity starter with ease or integrate with Commerce Layer.
Commerce Layer is a transactional commerce API and order management for international brands. It lets you make any digital experience shoppable, anywhere. You can build a multi-language website with Shopify, Contentful, WordPress, or any other CMS you already love. Then, add Commerce Layer for multi-currency prices, distributed inventory, localized payment gateways, promotions, orders, subscriptions, and more.
Unlike traditional solutions, Commerce Layer was built for the new era. It natively supports the most modern development workflows, such as the Jamstack. Ecommerce businesses can integrate Commerce Layer with a single backend and serve on multiple presentation layers enabling them to build outstanding shopping experiences, go headless, and scale their business globally. You can check out our developer resources to learn more and get started.
The Sanity studio is an open-source content management system built with React.js. It offers rapid configuration, free form customization, reusable structured content, a comfortable editor, real-time collaboration, toolkits, plugins, and more features to enable you to create the best content workflow.
Sanity provides the possibility to create starter templates that can be re-used by developers easily. The starter is primarily a repository hosted on GitHub that contains some meta-information, demo content, schema, and frontend(s) that will end up in a new repository when a developer installs the starter through sanity.io/starters. When a developer installs the starter, Sanity creates a new project on Sanity and a new repository on GitHub with the starter code, attaches a new Sanity datasetId
to the starter, and deploys the project to Netlify simultaneously.
Generally, a sanity starter can include a Sanity studio, a frontend application, both or multiple frontends and studios. For the purpose of this tutorial, we will create a starter that will include a studio and frontend. Our starter will include:
An ecommerce storefront built with Nextjs and Commerce Layer react components library.
International shopping capabilities powered by Commerce Layer APIs.
Some ecommerce data imported using the Commerce Layer CLI.
Structured content on Sanity studio.
Localization support.
Deployment configuration settings to Netlify.
Sanity has a defined specification for starters which includes some required files and directories. These specifications provide information about the starter to developers using the starter and make the project function as a reusable starter. Below is the folder structure of a Sanity project with required files and directories (without any frontend added):
├── .sanity-template
├── .sanity-template/assets
├── .sanity-template/data
├── .sanity-template/manifest.json
├── README.md
.sanity-template
is the root directory where all meta-information for using this repository as a template on sanity.io/starters is stored..sanity-template/assets
is the directory for storing assets related to displaying information about the starter. In this case, preview images for the overall project and for each site the starter contains..sanity-template/data
is the directory to store a Sanity dataset export if you want the starter to launch with some demo content..sanity-template/manifest.json
is the JSON file containing details about the Starter as well as deployment information.README.md
is the markdown file for this project that will be displayed on the Create page.
For a finished starter project, the root of the project should contain all deployable code, including the frontend and studio. Generally, a project spun from a starter is split into three parts:
/studio
directory for all studio code..sanity-template
for all starter meta-information.
Here is a sample from the Commerce Layer sanity starter as seen in the image below:
In this section, you will learn how we built a starter with an ecommerce application with transactional functionalities powered by Commerce Layer APIs, structured content on Sanity, imported seed data, and deployment configuration to Netlify. If you want to follow along with the guide, you can take a look at the finished project on GitHub here or even install the starter here.
Here is a sequential breakdown of all the steps taken to develop a starter:
Sanity has a command-line interface that we can use to interact with Sanity, create new projects, manage datasets, import data, and much more from the CLI. We'll use this CLI to set up a new sanity project following the steps below:
1: Install the CLI
Run the command below to install the Sanity CLI.
npm install -g @sanity/cli
2: Create a new project
Run the command below to bootstrap a new project which will log you into Sanity, create a new project, set up a dataset, and generate the files needed to run the studio environment locally.
sanity init
3: Run the studio
Run the command below to build the initial JavaScript code required to run the studio, and start a local web server.
sanity start
The studio should now run on [localhost:3333](http://localhost:3333)
. You can always run sanity help
to get an overview of other available and useful commands in the Sanity CLI.
Now that we understand how Sanity works and have set up a new sanity project, let's structure our sanity studio schema. Sanity schema defines how your content should be modeled, and this structure reflects in the studio UI. The schema describes the different field types a document consists of. Sanity uses the schema.js
file in the /schemas
directory to determine the content model of the project.
With Sanity, you define a block of content as a document or split your documents into modules and import them into the parent schema.js
file. Generally, there are three categories of Sanity schema types:
You can find all of the Sanity’s types in this reference documentation or learn how to structure your content model based on your needs by reading this comprehensive guide. For the Commerce Layer starter, our schema.js
looks like so in the snippet below with imports of several other module documents. You can view the schema code for each module here in the GitHub repository.
import createSchema from 'part:@sanity/base/schema-creator'
import schemaTypes from 'all:part:@sanity/base/schema-type'
// We import object and document schemas
import product from './product'
import country from './country'
import variant from './variant'
import size from './size'
import taxon from './taxon'
import taxonomy from './taxonomy'
import catalog from './catalog'
import blockContent from './blockContent'
import productImage from './productImage'
import localeString from './locale/String'
import localeText from './locale/Text'
import localeSlug from './locale/Slug'
import localeBlockContent from './locale/BlockContent'
// Then we give our schema to the builder and provide the result to Sanity
export default createSchema({
// We name our schema
name: 'default',
// Then proceed to concatenate our document type
// to the ones provided by any plugins that are installed
types: schemaTypes.concat([
// The following are document types which will appear
// in the studio.
product,
country,
variant,
size,
taxon,
taxonomy,
catalog,
// When added to this list, object types can be used as
// { type: "typename" } in other document schemas
productImage,
blockContent,
localeString,
localeText,
localeSlug,
localeBlockContent,
]),
})
If you are working on a new project like we did when we began developing the starter, you will have to manually add content to your project using the Sanity studio running on [localhost:3333](http://localhost:3333)
. The studio should now have the content fields populated with the configured content schemas in the “Desk” view. You can use that to add content to your project, as seen in the screenshot below.
If you are starting a new project using a starter or a previously saved project, then you can easily import a dataset with saved data following the steps below:
production.tar.gz
file in /.sanity-template/data
directory using the command below:tar -xf production.tar.gz
The extracted folder name should look like production-export-2021-02-26t14-15-56-557z
.
/studio
to import the data.ndjson
file in the extracted folder.sanity dataset import ../.sanity-template/data/<name of extracted folder>/data.ndjson <your_dataset>
You should check the running Sanity studio now to preview the imported content.
Before you add all frontend code to the root directory, you should move the Sanity studio code into a directory named /studio
.
At this stage, you will add the frontend code of your project, which can either be a blog, marketing website, CRM, or storefront. The major thing to do here is to use any of the Sanity client libraries to integrate Sanity into your frontend and fetch data. In our case, we used the official Javascript client that works in Node.js and modern browsers.
import sanityClient from '@sanity/client'
const client = sanityClient({
projectId: process.env.SANITY_PROJECT_ID as string,
dataset: process.env.SANITY_DATASET as string,
useCdn: process.env.NODE_ENV === 'production', // `false` if you want to ensure fresh data
})
Here’s an example of how we query Sanity to fetch the country and product data:
import _ from 'lodash'
import {
SanityCountry,
SanityProduct
} from './typings'
//Countries
const sanityAllCountries = async (locale = 'en-US') => {
const lang = parseLocale(locale, '_', '-', 'lowercase')
const query = `*[_type == "country"]{
name,
code,
marketId,
defaultLocale,
"image": {
"url": image.asset->url
},
'catalog': {
'id': catalog->_id
}
} | order(name["${lang}"] asc)`
const countries = await client.fetch<SanityCountry[]>(query)
return countries.map((country) => {
const localization = {
name: country?.name[lang],
}
return { ...country, ...localization }
})
}
//Products
const sanityGetProduct = async (slug: string, locale = 'en-US') => {
const lang = parseLocale(locale, '_', '-', 'lowercase')
const query = `*[_type == "product" && slug["${lang}"].current == "${slug}"]{
name,
description,
reference,
slug,
'images': images[]->{
'url': images.asset->url
},
'variants': variants[]->{
label,
code,
name,
size->,
'images': images[]->{
'url': images.asset->url
}
}
}`
const item: any[] = await client.fetch(query)
return parsingProduct(_.first(item), lang)
}
You can explore all our queries for the Commerce Layer starter project here in the GitHub repository. Also, here’s the major code powering our frontend alongside some hooks, utils, components, and dependencies.
Now that you have a Sanity Starter set up, we’ll show you the foundation principles needed to integrate commerce data from Commerce Layer. This is where you will begin to see the powerful combination of Commerce Layer data with Sanity content. And by the end of the tutorial, you will see not only the benefits of this integration, but you will also be able to experiment with your commerce data next to Sanity to see the power of both tools together.
In the starter we built, transactional functionalities of your ecommerce platform are managed by Commerce Layer, while the content is managed by Sanity studio. This will result in better order management and content management. To get started with using Commerce Layer, you will need to create an organization, perform some configurations and settings for your business, seed some demo data, and get your API credentials. The API credentials will allow you to interact with Commerce Layer in your presentation layer (frontend) and the CLI. To get the required credentials, kindly follow the steps below:
Website
. Upon successful creation, you'll get a CLIENT ID
, BASE ENDPOINT
, and ALLOWED SCOPES
. Kindly remember to save that as we'll use it to interact with our application later.CLI
and role: Admin
. Upon successful creation, you'll get a CLIENT ID
, CLIENT SECRET
, and BASE ENDPOINT
. Kindly remember to save that as we'll use it to interact with the CLI later.The official Commerce Layer CLI helps you to manage your Commerce Layer applications right from the terminal. Installing the CLI provides access to the commercelayer
command. You can set it up using the following steps:
//npm
npm install -g @commercelayer/cli
//yarn
yarn global add @commercelayer/cli
commercelayer applications:login -o <organizationSlug> -i <clientId> -s <clientSecret> -a <applicationAlias>
Now, with the steps below, you can use the CLI to import three demo markets (UK, USA, and Europe), a set of product SKUs, related price lists, related prices, stock locations, and inventory into your organization using the multi_market business model.
commercelayer plugins:install seeder
commercelayer seed -b multi_market
sanity-template-
.sanity-template.json
and add deployment configuration for the frontend web application and Sanity studio like so:{
"version": 2.0,
"title": "Commerce Layer Starter",
"description": "A multi-country ecommerce starter built with Sanity Studio, Commerce Layer, Next.js, and deployed to Netlify.",
"previewMedia": {
"type": "image",
"src": ".sanity-template/assets/preview.jpg",
"alt": "Preview image with Commerce Layer, Nextjs, and Netlify's logo"
},
"technologies": [
{
"id": "nextjs",
"name": "Next.js",
"url": "https://nextjs.org"
},
{
"id": "commercelayer",
"name": "Commerce Layer",
"url": "https://commercelayer.io"
},
{
"id": "netlify",
"name": "Netlify",
"url": "https://netlify.com"
}
],
"deployment": {
"provider": "netlify",
"sites": [
{
"id": "studio",
"type": "studio",
"title": "Commerce Layer Starter Studio",
"description": "A multi-country ecommerce starter built with Sanity Studio, Commerce Layer, Next.js, and deployed to Netlify.",
"dir": "./studio",
"previewMedia": {
"type": "image",
"src": ".sanity-template/assets/studio.png",
"alt": "A preview image of the Sanity studio."
},
"buildSettings": {
"base": "studio",
"dir": "/dist",
"cmd": "npm run build"
}
},
{
"id": "web",
"type": "web",
"title": "Commerce Layer Starter Web",
"description": "A multi-country ecommerce starter built with Sanity Studio, Commerce Layer, Next.js, and deployed to Netlify.",
"dir": "./web",
"previewMedia": {
"type": "image",
"src": ".sanity-template/assets/preview.jpg",
"alt": "A preview image of the web demo."
},
"buildSettings": {
"base": "/",
"dir": "/out",
"cmd": "npm run build"
}
}
]
}
}
The metadata information is primarily displayed on sanity.io/create as described below by the visual explainer from Sanity docs.
sanity-template.json
file for errors using the sanity-template command:sanity-template check
sanity-template.json
using the command**:**sanity-template build
name
, projectId
and dataset
in studio/sanity.json
to a dynamic variable so when a user installs your starter via sanity.io/starters, Sanity can populate it with new values. To this, you pass the string value in <#< ... >#>
as seen in the snippet below: {
"root": true,
"project": {
"name": "<#< sanity.projectTitle >#>",
"basePath": "/"
},
"api": {
"projectId": "<#< sanity.projectId >#>",
"dataset": "<#< sanity.dataset >#>"
}
}
studio/package.json
. All you need to do is add a renovate.json
to the root directory, with the following configuration:{
"extends": [
"github>sanity-io/renovate-presets:sanity-template"
]
}
<your-project>.sanity.studio
URL. You can also deploy anytime you make any change to your studio.sanity deploy
PS: You can still host a studio on any cloud platform you choose too (here’s how to deploy to Netlify) so you don't have to manually deploy after every change.
https://www.sanity.io/create?template=[githubhandle]/sanity-template-[starter-name]
Now that you have built a Sanity starter and integrated Commerce Layer, you can start to add more items and product data stored in Commerce Layer so you can see how your products and prices show up within your content. The power of Commerce Layer is that you can really localize your commerce data to make it work for multiple markets, all of which likely have different prices, SKUs, promotions, and even simple things like item weights and measurements. Commerce Layer gives you tremendous flexibility to sell your products locally and paired with a powerful tool like Sanity, you will be on your way to building the best, most optimized shopping experience for your customers.
You can get started with the Commerce Layer starter by visiting this link, creating a new project and following the instructions in the link. Feel free to join the Commerce Layer Slack community to share what you are able to build after reading this tutorial or showcase the starter on Sanity. For further knowledge, you can learn the central concepts needed to create a 1-click Sanity Starter, learn how to build headless commerce web experiences with Commerce Layer, or learn how to sell internationally with a single Shopify store and Commerce Layer.
Thanks for reading! 🖤
Also Published Here