Marketplace Kit 2.0: Decoupling From the CLI

In February, Shopify released the second version of Marketplace Kit — a collection of boilerplate app code and documentation that lets third-party developers integrate with Shopify and launch a marketplace in any channel. Version 1.0 was built on the Node app generated by the Shopify CLI, which had two main drawbacks: changes to the CLI could ripple into the kit's code and docs, and the team had limited control over best practices because the CLI dictated the dependencies.

Marketplace Kit 2.0 decouples the sample code from the CLI and splits it into two separate open-source apps: a full-stack admin app for merchants and a buyer-facing client app. Both use widely adopted dependencies — Express and NextJS, with React on the frontend — to appeal to the broadest possible partner audience. The admin app runs on Node JS with Express; the buyer app uses Next JS for structure, server-side rendering and built-in TypeScript support. Data sharing between frontend and backend relies on GraphQL with Apollo Client and Apollo Server.

Here's a look at the key API decisions behind the merchant-facing admin app.

Handling Authentication With App Bridge

For embedded apps, Shopify's App Bridge library provides React component wrappers and out-of-the-box support for embedding inside the Shopify admin, POS, and mobile apps. The admin app uses additional App Bridge imports to manage authentication. The client-side example wraps authenticatedFetch inside a custom function that handles auth redirects:

Two important things happen under the hood. The authenticatedFetch import silently adds an Authorization header with a JWT session token created on demand, plus an X-Requested-With header set to XMLHttpRequest, which narrows the request type and improves security. The app object, an instance of useAppBridge, supplies the contextual information about the embedded app.

On the server side, the main server file defines the GraphQL server and uses an Express app as middleware. Inside the configuration of the ApolloServer's context property, the session token is decoded and the session data is loaded — both handled by Shopify's Node API, which yields the store's access token. To test with additional stores, swap out the store value in .env and run the Shopify CLI's shopify app serve command.

Serving REST and GraphQL Together With Express

The server code uses the apollo-server-express package rather than bare apollo-server. The setup is nearly identical, with one key difference: the Apollo Server instance is applied as middleware to an Express HTTP instance via graphQLServer.applyMiddleware({ app }).

In the full file, webhooks and Express routes are added after the GraphQL server starts. That's the main advantage of the Express-specific package — being able to serve REST and GraphQL from the same server, which allows Node middleware for rate-limiting, security, and authentication. The trade-off is slightly more boilerplate, but since apollo-server is simply a wrapper around the Express version, there is no noticeable performance difference.

Custom Client Wrappers for Flexibility

The admin app also defines custom API clients for data fetching from Shopify's Node API, covering both GraphQL and REST. This gives the team easier control over request configuration, such as adding custom User-Agent headers with a unique header title for the project and its npm package version.

GraphQL is generally encouraged, but REST still has its place. The admin app uses a single REST call to retrieve the product listings count — an HTTP-GET request contains all the needed information, so a GraphQL query would add no value. It also ensures that developers using the admin app as a starting point see a working example of both data-fetching approaches, with guidance on when each makes sense.

Getting Started

Full setup instructions are available in the official Marketplace Kit documentation. The embedded admin app and buyer app screenshots below show what you can expect after completing the tutorials.