Build a Shopify App in less than an Hour

50 Min Read

Who should use this tutorial?

A developer that is looking to build an example Shopify app from start to finish and deploy it.

I used the official Shopify app boilerplate tutorial when I first started Shopify app development. It was a good starting place, but it left out key components to building a Shopify app. For example, the tutorial does not explain how to store user information and user preferences in a database. Finally, it wasn't obvious on how to deploy the Shopify app from a local environment to a production environment. I created this Shopify framework tutorial to address these issues and build a working example app from start to finish.

The working example will allow a user to select products and then apply a pricing discount. During this tutorial, you will learn the most important concepts:

  1. How to embed a Shopify app in the admin dashboard.
  2. Create a UI/UX that has the same look and feel as Shopify.
  3. Get a list of products from the store, apply discounts to products.
  4. Charge a customer a monthly fee.
  5. Move the app from local development to host the Shopify app in production.
  6. Add a database to store user information.

What you'll need to get started.

I'll supply you with the complete code for the Shopify app, but it helps if you have an understanding of front end and back end javascript frameworks.

Setup the Shopify app.

This app uses Node.js, and Next.js (React Framework) to create the Shopify app.

  1. Check if you have Node.js from your terminal:

{% c-block language="bash" %}
$ node -v
{% c-block-end %}

  1. If it is not installed, then make sure you get the latest version of Node.js.
  2. Create a new directory for the Shopify app.

{% c-block language="bash" %}
$ mkdir shopify-complete-app && cd shopify-complete-app
{% c-block-end %}

  1. Initialize the directory for Node.js with a package.json.

{% c-block language="bash" %}
$ npm init -y
{% c-block-end %}

  1. Install React and Next.js

{% c-block language="bash" %}
$ npm install --save react react-dom next
{% c-block-end %}

  1. Create a pages directory in the app project directory

{% c-block language="bash" %}
$ mkdir pages
{% c-block-end %}

  1. Create a file pages/index.js with the code:

https://gist.github.com/nutterbrand/5f887fc3721c95a142399d5631ad1139

export default Index;
{% c-block-end %}

  1. Add start, stop, and build commands and replace the code of package.json file:

https://gist.github.com/nutterbrand/44465ec2f8012a0f6f25d324a44d9902


Install the Shopify App

This section will cover everything you need to embed your Shopify App in the store.
  1. In a new terminal window, install ngrok:

{% c-block language="bash" %}
$ npm install ngrok -g
{% c-block-end %}

  1. Set ngrok to use port 3000:

{% c-block language="bash" %}
$ ngrok http 3000
{% c-block-end %}

  1. Leave this terminal alone since now it is forwarding your localhost:3000 to your new ngrok address.
  2. Create a new app in the Shopify Partner Dashboard. If you do not have a partner account, create one.
  3. From your Shopify Partner Dashboard, create a new app:
Select Apps and Create App
  1. Copy the https address in ngrok:
  1. Select a public app and copy in the app name Complete App Example and use your ngrok address in the following highlighted lines. Remember to put /auth/callback at the end of the redirection URL.
  1. Once you create the app, copy the API key and API secret key from the app dashboard.
  1. Create a .env in your project folder with the following contents. I'm using Vim to make edits, but use the editor of your choice:

{% c-block language="bash" %}
$ vim .env
{% c-block-end %}

https://gist.github.com/nutterbrand/5367cd54157d5e5740fb28e133eee09e

  1. In a new terminal window, install koa and the Shopify koa auth middleware:

 {% c-block language="bash" %}
$ npm install --save koa @shopify/koa-shopify-auth dotenv koa-session isomorphic-fetch
{% c-block-end %}

  1. Create a server.js that starts Node.js, authenticates Shopify, and handles incoming requests in your project folder and copy in the contents:

https://gist.github.com/nutterbrand/12eac56b53cccd5c73a4dbd26a064552

  1. Update the scripts section of package.json to run the Shopify app:

https://gist.github.com/nutterbrand/d0fce636e8c8435cde07c898d61d34c4

  1. In your original terminal window (not your ngrok window) start your server:

 {% c-block language="bash" %}
$ npm run dev
{% c-block-end %}

  1. In the Shopify partner dashboard, click the Select store inside Test your app.
  1. Click Create new store.

  1. Create a new store with the name of your choosing and click save.
  1. If successful, the new store should look like the below image:
  1. Now, go back to your Shopify dashboard (the URL should look similar to the highlighted URL) and click into the apps section and select your new app and finally Select store to select your new store.
  1. Once the dialogue box pops up, select Install anyway and you click Install unlisted app.
  1. You should now see the URL of your test store highlighted and text on the screen Sample app using React and Next.js

Work on the user interface

Shopify uses a design system they created called Polaris it serves as an opinionated UI/UX framework. Polaris makes it easy and fast to develop user interfaces the framework is very opinionated. In this next section you will see how fast and easy it is to use.

Polaris, Shopify's UI/UX framework makes UI design extremely easy, even for a back end developer.

  1. Install Polaris in your project directory:

{% c-block language="bash" %}
$ npm install --save @zeit/next-css @shopify/polaris
{% c-block-end %}

  1. In your project directory, create a next.config.js file with the folloing code:

https://gist.github.com/nutterbrand/0ebbbbb3e102748954c0666821d9d5e7

  1. Add the Polaris package into your Next _app.js configuration:

https://gist.github.com/nutterbrand/23bd2262fc6dbe41f71b864773e0aa7c

  1. Restart your webserver:

 {% c-block language="bash" %}
$ npm run dev
{% c-block-end %}

  1. Updates pages/index.js to use Polaris elements:

https://gist.github.com/nutterbrand/5401a143c9f2e786003748c76c90b1e6

  1. Setup the configuration layout with Polaris and create a new file pages/annotated-layout.js

https://gist.github.com/nutterbrand/c0865f7b0c86d4a952dd1d88fd8f0b2c

  1. Sign in to the Shopify Partner Dashboard, and click Apps > sample-embedded-app to navigate to your app.
  1. Click on Manage under Embedded app
  1. Click on Configure in the Navigation section.
  1. Add the two navigation links from the pictures below:
  1. Redirect on Shop parameters in the URL -- Replace the contents of the server.js:

https://gist.github.com/nutterbrand/22293ab0c590ef55a903411da57993fe

  1. Install the App Bridge package in your terminal:

 {% c-block language="bash" %}
$ npm install --save @shopify/app-bridge-react
{% c-block-end %}

  1. Update your Next.js pages/_app.js file to have the Shopify app bridge:

https://gist.github.com/nutterbrand/eda9c460980148a03f2faf909edf4c37

  1. Restart your webserver:

 {% c-block language="bash" %}
$ npm run dev
{% c-block-end %}

  1. Add the title bar and update pages/index.js

https://gist.github.com/nutterbrand/5d6a74b648ee193c50c4bdb0b16cbc9d

  1. Add the client router in components/ClientRouter.js

https://gist.github.com/nutterbrand/d1a94ac5370644a849e7eb72edacc7a9

  1. Update pages/_app.js to have the client router:

https://gist.github.com/nutterbrand/2c8f59b847356170ff8b7ff6799b3550

  1. Update pages/index.js to have the resource picker:

https://gist.github.com/nutterbrand/cd52d4348a8c59bd900c1ca426d619ce

  1. Download and save the following products_example.csv
  2. Go to your test store as in the highlighted URL and click on All products and click Add product
  1. Click Upload and continue
  1. Click Import products
  1. If successful, the products should now be imported:
  1. Update pages/index.js and add the resource picker to your title bar and pass data from the resource picker:

https://gist.github.com/nutterbrand/d0a310038141107cde0b129be9f52148

  1. Finally, let's take a look at the Polaris Annotated Layout in your app installed on the test store:

Get store data from Shopify API

Shopify uses a GraphQL and Apollo to fetch store data and then return it for use. Store data can include orders, inventory, and metadata. In this next section I'll show you how to retrieve store data for your Shopify app. If you want to learn the graphQL admin api, Shopify provides a good tutorial on covering the basics. Everything you will need will be in the next section to complete the app to interface with GraphQL.

Shopify uses GraphQL and Apollo to retrieve merchant store data

  1. Stop your terminal that is running your node server and install GraphQL and Apollo libraries:

 {% c-block language="bash" %}
$ npm install --save graphql apollo-boost react-apollo
{% c-block-end %}

  1. Install koa-shopify-graphql-proxy

 {% c-block language="bash" %}
$ npm install --save @shopify/koa-shopify-graphql-proxy
{% c-block-end %}

  1. Update server.js with GraphQL in middleware, updated permissions to write products, and call out a specific version of the API:

https://gist.github.com/nutterbrand/c23bfad5a46754e755a4a2b9fd6379de

  1. Add in the Apollo client in Next.js in pages/_app.js:

https://gist.github.com/nutterbrand/d86edfb0975e34f7c36769f6c54b2747

  1. Create a file components/ResourceList.js that will fetch the products from the Shopify API and bring back a list of products:

https://gist.github.com/nutterbrand/4c41be8de143b79f273cd54825c444f5

  1. Use localstorage to store user selected products by installing store-js in your terminal

 {% c-block language="bash" %}
$ npm install --save store-js
{% c-block-end %}

  1. Update pages/index.js to store products in localstorage and include the ResourceList component:

https://gist.github.com/nutterbrand/f40f03bccb74eb1925ee59e4380b23cd

  1. Build a Polaris UI for the components/ResourceList.js:

https://gist.github.com/nutterbrand/5ac1d5080c226f86ac7d9be00b9bd5f9

  1. Get the product IDs from the stored local session by updating the contents of pages/index.js:

https://gist.github.com/nutterbrand/3387a9a83a08990e6868b4df0608c103

  1. Take a look at your app in the test store and click on Simple resource picker to see the list of products you've selected or click on Select products to first select products, and then see the Simple resource picker:
  1. Create an pages/edit-products.js which will allow a user to update the price of the product:

https://gist.github.com/nutterbrand/8417348cafc45dde43b98c58778162b7

  1. Add the context and the redirect logic for app bridge by updating the contents of components/ResourceList.js:

https://gist.github.com/nutterbrand/c0a74e2dc6cb7184825b77c658351850

  1. Update pages/edit-products.js to write the price change back to Shopify and give the user a success message:

https://gist.github.com/nutterbrand/a36e89dffa77154c9cfc1134cc6ce2b9

  1. Finally, see the write back to Shopify in action with the edit-products screen, found via Select products


 

Setup billing in Shopify.

One of the things I love the most about creating Shopify apps is Shopify handles the billing transparently for the customer. For the customer, this means they never have to enter a credit card number to use your app. They simply need to consent authorization and then Shopify will handle it from there. This also means that Shopify will take a 20% cut of your revenue so you need to plan your pricing model so that you will still make money even after the 20%.

The customer only sees the pricing charge once at installation if you are billing the customer on a monthly basis. Furthermore, if the customer uninstalls the app, then they will not be charged at that time.

The following section will show you how to set up monthly billing for $10 when the customer installs your Shopify app.

Shopify handles billing transparently through their system; The customer will be billed for your app on their next Shopify payment cycle.

  1. Add the HOST and API_VERSION to your .env file in your project:

https://gist.github.com/nutterbrand/4bd9afe396c368698a3f553b8b950adf

  1. Make the payment request to Shopify and redirect to a confirmation page by creating a new file under this new directory server/getSubscriptionUrl.js:

https://gist.github.com/nutterbrand/d49a34e2624318f54b627258af43c047

  1. Update server.js to use the SubscriptionURL component and to redirect after a successful billing:

https://gist.github.com/nutterbrand/316fc5ccb3bcd85d75e6cf9fdb0bb702

  1. Let's test the new payment module, Deleting the current app and then reinstalling:
  1. Now go back to your Shopify Partner dashboard and go to your App, Test on Store, and select your test store that you just uninstalled the app on:
  1. Click Install unlisted app:
  1. Approve subscription:
  1. Once you approve the plan, then you should successfully see the installed app:

Setup Shopify app hosting and Postgres on Heroku.

If you are developing an app for yourself or for a client, it is important to understand how to host the Shopify app. In this next section, I will show you the steps to host your app on Heroku. I chose Heroku since it is extemely easy to launch and most of the setup I can do through command line. The cost for the service should be less than $50 a month for most applications of an app.

  1. Sign up for Heroku.
  2. Install the Heroku command line tools. See this guide on how to install.
  3. Login with Heroku command line:

 {% c-block language="bash" %}
$ heroku login
{% c-block-end %}

  1. Initialize your git in your current project directory:

 {% c-block language="bash" %}
$ git init
{% c-block-end %}

  1. Create a new Heroku project:

 {% c-block language="bash" %}
$ heroku create
{% c-block-end %}

  1. Create the Postgres database for the new project. This is hobby-basic database for $9 a month to start with that will support up to 10 million rows:

 {% c-block language="bash" %}
$ heroku addons:create heroku-postgresql:hobby-basic
{% c-block-end %}

  1. View the new credentials of data database in the environment variable: DATABASE_URL:

 {% c-block language="bash" %}
$ heroku config
{% c-block-end %}

  1. The DATABASE_URL will be structured like the following: 

 {% c-block language="bash" %}
DATABASE_URL=postgres://PGUSER:PGPASSWORD@PGHOST:PGPORT/PGDATABASE
{% c-block-end %}

  1. Create PG_* environment variables on Heroku for Postgres from the DATABASE_URL variable by replacing the YOUR_* with actual values. Also, add in the other env variables for Shopify:

 {% c-block language="bash" %}
$ heroku config:set PGUSER=YOUR_PGUSER
{% c-block-end %}

 {% c-block language="bash" %}
$ heroku config:set PGPASSWORD=YOUR_PGPASSWORD
{% c-block-end %}

 {% c-block language="bash" %}
$ heroku config:set PGHOST=YOUR_PGHOST
{% c-block-end %}

 {% c-block language="bash" %}
$ heroku config:set PGDATABASE=YOUR_PGDATABASE
{% c-block-end %}

 {% c-block language="bash" %}
$ heroku config:set PGPORT=YOUR_PGPORT
{% c-block-end %}

 {% c-block language="bash" %}
$ heroku config:set SHOPIFY_API_KEY=YOUR_SHOPIFY_API_KEY
{% c-block-end %}

 {% c-block language="bash" %}
$ heroku config:set SHOPIFY_API_SECRET_KEY=YOUR_SHOPIFY_API_SECRET
{% c-block-end %}

 {% c-block language="bash" %}
$ heroku config:set SCOPES=read_products,write_products
{% c-block-end %}

 {% c-block language="bash" %}
$ heroku config:set API_VERSION=2019-10
{% c-block-end %}

 {% c-block language="bash" %}
$ heroku config:set HOST=https://YOUR_HEROKU_APP_NAME.herokuapp.com/
{% c-block-end %}


  1. Check to make sure all the PG* environment variables are set by running this command:

 {% c-block language="bash" %}
$ heroku config
{% c-block-end %}

  1. Set Heroku to be your production environment:

 {% c-block language="bash" %}
$ heroku config:set NODE_ENV=production
{% c-block-end %}

  1. Update your local .env file to match. Important Note: Your dev environment should have a dev database in the future and should not share the production database. It is fine now, but put this on your checklist of items to do in the future:

https://gist.github.com/nutterbrand/3f3d3e85e1063adb2981346a0a1cbfa6

  1. Go into the Shopify Partner dashboard and into the app settings and change the App URL and the Whitelisted redirection URL(s):
  1. Create a .gitignore file to ignore any local files which will conflict with Heroku:

https://gist.github.com/nutterbrand/11a46b62a2f9f305aa12532768342ffa

  1. Add your files to git:

 {% c-block language="bash" %}
$ git add .
{% c-block-end %}

  1. Commit your changes:

 {% c-block language="bash" %}
$ git commit -m "Adding changes from Shopify tutorial"
{% c-block-end %}

  1. Push to Heroku for deploymentr:

 {% c-block language="bash" %}
$ git push heroku master
{% c-block-end %}

  1. Add create shop table sql file in your project directory and save it as table.sql:

https://gist.github.com/nutterbrand/4fe6a6d21060f035276f7727578160ad

  1. Import this file into the Postgres database in Heroku:

 {% c-block language="bash" %}
$ heroku pg:psql --remote shopify-example < table.sql
{% c-block-end %}

  1. Start logging on Heroku production deployment, so you can watch it when you reinstall the app: 

 {% c-block language="bash" %}
$ heroku logs --app YOUR_HEROKU_APP_NAME --tail
{% c-block-end %}

  1. Uninstall the app from the test store, and reinstall the app now that it has the new App URL and Whitelisted URLs in step 13.
  1. Congratulations, you should now see a production version of your application running from Heroku as in the below:
  1. Check to see if the user is stored in the Heroku Postgres database:

 {% c-block language="bash" %}
$ heroku pg:psql
{% c-block-end %}

 {% c-block language="bash" %}
DATABASE=> select shop, user_email from public.shop;
{% c-block-end %}

Summary.

Together we just built a complete Shopify app from start to finish and deployed the app to Heroku. Most of what is covered in this tutorial you can build off to fetch other data from the Shopify API. Also, you can reuse this framework for multiple apps in the future which makes app development extremely quick. To understand how to set up a development, staging, and production workflow along with the final touches, sign up for the email to get my best practices!