Build a website with Gatsby and Strapi - Part 1: 12 steps to install and deploy Strapi
Tags: gatsby, react, webdev, strapi
Published: 2020-05-10 19:14:45

For the first part of this tutorial serie, we will see how to install, configure and deploy Strapi.

**Info : This tutorial serie is also available on [my website](https://tsflorus.me)**

If you have any problems or struggle with this tutorial, let me know in the comment section (I check the comments very often)

Also, let me know what you think of this tuto and if there is stuff that can be added.

As said in the [introduction article](https://tsflorus.me/blog/build-website-gatsby-strapi-introduction), Strapi is a powerful headless CMS that allows a lot of flexibility.

In this tutorial we will set both development and production environment.

- Production : on heroku with a postgresql database
- Development : on our local machine with the standard sqlite3 database

## Step 1 - Install Strapi on our machine

Be sure to match all the requirements before continue.

    - Node.js - 12.X minimum

    - npm - 6.X minimum

Our strapi project will be named "strapi-cms"

To create it, open a new terminal window and type the following line :

```bash
yarn create strapi-app strapi-cms --quickstart
```

Strapi is going to install all required dependencies, setup all needed files and an sqlite3 database for our local environment.

## Step 2 - Create an admin user

Now that Strapi is installed, a browser window will open. If it does not open, navigate to **[localhost:1337/admin](http://localhost:1337/admin)** and here is what you should see :

![create-admin-user](https://res.cloudinary.com/tsflorus/image/upload/v1589137310/create-admin-user_e2e17dff58.png)

We are now going to fill the form and click the "Ready to start" button.

> **Warning : This user will only be saved in our local sqlite3 database, we willl have to recreate it in production**

## Step 3 - Create our first collection type for our articles

Strapi works with objects named "Collection types". If you have already worked with an MVC structure, a collection type is the equivalent of a model.

In a collection we define :

    * Name

    * Fields

    * Relations with other collection types

To create one, let's take a look to the left sidebar

![sidebar](https://res.cloudinary.com/tsflorus/image/upload/v1589137317/sidebar_6070c2269e.png)

Click on **Content-Types Builder**

![CTbuilder](https://res.cloudinary.com/tsflorus/image/upload/v1589137312/CTbuilder_e5fb141ecf.png)

You can see that we already have 3 collection types :

- Permission
- Role
- User

They have been generated by strapi when we have created the project.

Now we are going to click on **Create new collection type.**

The display name of this new CT will be **article.**

![article-ct](https://res.cloudinary.com/tsflorus/image/upload/v1589137309/article-ct_e459eaa107.png)

We are asked to select the different fields of this CT.

![list-of-fields](https://res.cloudinary.com/tsflorus/image/upload/v1589137314/list-of-fields_8c9ca4936a.png)

This is the list of the different fields we need with their names and types. After adding a field, click on **Add another field** until you reach the end of the list.

For our article we will select :

- **Text** for the title → **Short text named title**
- **Date** for the publication date → **Date named date**
- **Text** for the description → **Long text named description**
- **Media** for a cover picture → **Single media named cover**
- **Rich Text** for the content → **named content**

We have now created our article collection type. Let's now hit the **save** button on the top right corner of the page.

### What have we done ?

If we think in an MVC way, we have set up our database and our models. We have specified that we have a table named "article" in which we will find different fields called : title, date, description, cover and content.

This model is directly saved in our project as a json file (Which we will see a little bit later)

## Step 4 - Create other collection types

We already have an article CT. But we need to add some extra fields. 

As we are building a blog, it would be awesome to also have tags on each of our articles. It will allow us to create a search function and list every articles of a specified tag.

Let's add a CT named **tag**. To do that, just follow the steps of the article CT creation and specify these fields:

- **Text** for the name → **Short text named name**

That's all. We don't need anything else.

As this CT is created, let's link it to our article CT so we will be able to add tags to each articles.

Go on the article CT and click **Add another field** then add a **relation** field and on the right side, select the **Tag** CT.

> Let's speak about cardinality. If you ever worked with databases and created one, you will know that cardinality are very important. They allow us to know how much **A** have and/or belongs to **B.** Thanks to this result, the database creator will know if he has to create a new table or just a simple field.

> In our case **Articles has and belongs to many Tags,** We have a cardinality of 1-1 (or * - * ) so we have to create a table, which is what we have done creating a new CT.

As I said, **Articles has and belongs to many Tags.** We now have to specify it by selecting this icon:

![cardinality](https://res.cloudinary.com/tsflorus/image/upload/v1589137309/cardinality_8900edabf9.png)

Click **Finish**, then **Save** and we are all set.

> We will certainly add other fields or CT during this tutorial serie. When it will be the case, I will give you the list of fields and types you have to create.

## Step 5 - Create an app on [Heroku](https://heroku.com)

Our Strapi app is now all set but we can access it only via localhost. We now have to put this app in production in order to access it from anywhere.

We will use **[Heroku](https://heroku.com).** which is a Cloud application platform that allows you to host, deploy and serve web-apps.

You can get a free dyno here (not a sponsored link)

Personally, I have free a Hobby dev thanks to github education pack.

Once your account is created, we will add a new app. For me, this app is called **tsflorus-strapi-tutorial** and I have choose **Europe** for the region as I am in France.

Our heroku app is now created.

![heroku-created](https://res.cloudinary.com/tsflorus/image/upload/v1589137314/heroku-created_693d02d047.png)

## Step 6 - Add the postgres add-on to our Heroku app

As said at the beginning of this tuto, we need to setup a database along with our strapi instance.

### Why ?

As Heroku is a cloud platform, when you will not be using your dyno, it will go into a sleep. Annd every-time the dyno will start, you will loose your data including articles, tags etc.

We will be using a postgreSQL database with the **Heroku-postgres** add-on.

To add this add-on, click on **Ressources** on the top navbar then search for **Postgres** in the Add-ons section.

![postgres-addon](https://res.cloudinary.com/tsflorus/image/upload/v1589137317/postgres-addon_0e96ff0462.png)

Click on the right add-on then select your plan. For this tutorial we will go one a Hobby Dev plan.

![hobby-dev-plan](https://res.cloudinary.com/tsflorus/image/upload/v1589137315/hobby-dev-plan_721f5f93bf.png)

## Step 7 - Add our database information in the config vars

In order to secure our Strapi app, we will not put our database information directly in our config file but we will use environment variables.

To set environment variables inside of our Heroku app, go to **Settings** on the top navbar.

![settings](https://res.cloudinary.com/tsflorus/image/upload/v1589137319/settings_5fb23806a0.png)

Let's click on **Reveal Config Vars**

We now see a var called **Database URL** and its value is a very long string such as this one:

```
postgres://fisojprjbmfmpl:e94f1e76a464632410d8246b47eca1e3f0f78e817165c9a7e5a22013f5499025@ec2-176-34-97-213.eu-west-1.compute.amazonaws.com:5432/da2n7sjsnqblr5
```

This URL contains every information of our database, Name, Username, Password, Host, Port.

In this case we have :

- DATABASE_HOST =  ec2-176-34-97-213.eu-west-1.compute.amazonaws.com
- DATABASE_NAME = da2n7sjsnqblr5
- DATABASE_USERNAME = fisojprjbmfmpl
- DATABASE_PORT = 5432
- DATABASE_PASSWORD = e94f1e76a464632410d8246b47eca1e3f0f78e817165c9a7e5a22013f5499025

For each info, we have to create a new var. Once its done, your page will look like this.

![env-vats](https://res.cloudinary.com/tsflorus/image/upload/v1589137312/env-vats_2265ff31de.png)

Great.

## Step 8 - Configure your strapi database connection

The last step for setting up the database is to update the strapi configuration.

Let's open your favorite code editor on the root directory of your strapi project and go to **config/environments/production/database.json**

Make modifications in order to have exactly this file :

```json
{
  "defaultConnection": "default",
  "connections": {
    "default": {
      "connector": "bookshelf",
      "settings": {
        "client": "postgres",
        "host": "${process.env.DATABASE_HOST}",
        "port": "${process.env.DATABASE_PORT}",
        "database": "${process.env.DATABASE_NAME}",
        "username": "${process.env.DATABASE_USERNAME}",
        "password": "${process.env.DATABASE_PASSWORD}",
      },
      "options": {}
    }
  }
}
```

What we are telling to strapi here is to use our environment variables to get the database information. It will use the few vars we have created on the last step.

## Step 9 - Deploy your strapi app on heroku

Deploy an app to heroku is very easy. There are few ways to do it.

- Github hook → The app will rebuild every-time you update the default branch (master for example)
- Container registry → If you are using Docker you will be able to deploy your docker-based app to heroku from its CLI
- Heroku Git → Deploy an app directly with CLI by making it a Heroku repository

In out case, we will use the third method.

> Heroku git and github can be used in parallel.

First of all let's add a line to the .gitignore file.

```
package-lock.json
```

If you don't add package-lock.json in the gitignore file, it may cause problems on heroku.

Now, we will need to install a package named **pg**  which is a postgres package. If you forgot to install it, your build will be marked as succeeded but you will get an eroor when opening the app

![heroku-error](https://res.cloudinary.com/tsflorus/image/upload/v1589137313/heroku-error_a67db74eee.png)

If it was your case, just install pg package and redeploy your app. 

If you have already install **pg** go on your app with terminal and type 

```bash
heroku logs --tail
```

That will tell you where the problem is.


To install **pg** open a terminal window on the root directory of your Strapi project and enter the following command:

```bash
npm install pg --save
```

To deploy our application we need to go to the root folder of our Strapi app and follow theses steps :

1 - **Login with heroku**

```bash
heroku login
```

This will open a webpage so you can log in with your heroku crendentials

2 - **Initialize the git repository**

> If  you are using an existing git repository, skip this step

```bash
git init
```

3 - **Set the remote branch for our app** (here, tsflorus-strapi-tutorial has to be replaced with your heroku app's name)

```bash
heroku git:remote -a tsflorus-strapi-tutorial
```

4 - **Add all of our changes** 

```bash
git add .
```

5 - **Make a commit message**

```bash
git commit -m "Initialize my Strapi app"
```

6 - **Then, push to the master branch**

```bash
git push heroku master
```

Heroku will now build your Strapi app into your Dyno. You can see the build logs by clicking on **Overview** in the top navbar.

Once the build is noted as succeeded you will be able to see your app by clicking the **Open app** button on the top-right corner of your screen.

And you will see that your app is now running in production !

![app-in-production](https://res.cloudinary.com/tsflorus/image/upload/v1589137310/app-in-production_1de8b5b9f8.png)

We will now need to recreate an admin user. To do that, go on **[yourproject.herokuapp.com/admin](http://yourproject.herokuapp.com/admin)** replacing **yourproject** with your app name.

Exactly like we have done on the beginning, complete the admin user creation form then log in.

![strapi-dashboard](https://res.cloudinary.com/tsflorus/image/upload/v1589137319/strapi-dashboard_f4e5b6e54e.png)

Congrats ! You now have an instance of strapi running in production.

> Keep in mind that every-time you will make changes in development mode (locally) you will need to redeploy your strapi app to see them production. Plus, the entry you will add on development mode will not be added in the production mode as we are not using the same database. If you want, you can setup the same database for both dev and prod environments.

## Step 10 - Create our first tag and article

We are now going to create our first tag and article.

Let's click on the **Tags** CT on the left navbar, then click on **Add new Tag**. **** Our first tag will be named hello-world. Enter this name when you are asked to and click save.

Now that we have our tag, let's add an article.

Click on **Articles** on the left navbar and you should see this window:

![create-article](https://res.cloudinary.com/tsflorus/image/upload/v1589137310/create-article_0934fa5243.png)

Add the content of your choice for each fields and save your new entry.

> The content field is a markdown editor. If you don't now about markdown yet, check **[this link](https://www.markdownguide.org/cheat-sheet/)**

![article-content](https://res.cloudinary.com/tsflorus/image/upload/v1589137311/article-content_2aeea9959e.png)

Now, click on save and your article is saved !

## Step 11 - Adjust permissions

As an headless CMS, Strapi render content via an API (I will upload very soon an article on APIs). For short, it means that we will not fetch data with a database connection but directly via a URL.

By default, Strapi's API is secure so that anyone cannot query our data. For this tutorial, we will allow every public user to query data of our Strapi API.

!! **Disclaimer** !! Never do this for a real serious project ! We are going to remove user protection jsut for the needs of this tutorial. **Always secure your APIs !**

On the left navbar of Strapi's dashboard, click on **Roles & Permissions.**

You can see that we have two different user roles. An Authenticated and a Public user.

> Both roles are empty of user because we haven't add one. Your admin user isn't in the user table but just allow you to access this Admin Dashboard

![permissions](https://res.cloudinary.com/tsflorus/image/upload/v1589137317/permissions_1cb3ab37c7.png)

We will edit permissions for the Public user.

Once you have clicked on **Public**, you will see under Permissions our two CT : Article and Tag.

For both of them we are going to check **find** and **findone** checkbox.

> Note that on the right side you see a URL. In this case it is **/tags/:id.** This is the path we will have to use to fetch a specified tag.

![set-permissions](https://res.cloudinary.com/tsflorus/image/upload/v1589137320/set-permissions_93c98f5609.png)

We will also need to set this **find** and **findone** permissions for the **Users-Permissions** on the bottom of the page

![users-permissions](https://res.cloudinary.com/tsflorus/image/upload/v1589137322/users-permissions_03cf593291.png)

Let's click on save.

Now we are ready to fetch our first article !

## Step 12 - Fetch our first article

The default route for fetching your collection-types will be **[yourproject.herokuapp.com/collection-type](http://yourproject.herokuapp.com/collection-type)** where **yourproject** is the name of your app and **collection-type** the name of the CT you want to fetch.

You can fetch this data from anywhere just entering this URL. Personally, when I work with APIs I prefer to use a software named **Insomnia** which is a powerful tool for REST APIs.

If I fetch the CT **articles**, we will have this response:

> Always add an extra "s" at the end of your CT name in the URL. To fetch our **Article** CT, I have to enter this URL : [https://tsflorus-strapi-tutorial.herokuapp.com/articles](https://tsflorus-strapi-tutorial.herokuapp.com/articles)

```json
[
  {
    "id": 1,
    "title": "Hello world",
    "date": "2020-05-10",
    "description": "Just want to say hello to the entire world",
    "content": "# Oppugnant deus ficta fulva oculis manent lupis\n\n## Undis meminisse tum pariterque uterque iras lupum\n\nLorem markdownum Antiphatae moto, sis nuper, habuit coniunx, rursus. Volvens\nexamina, enim Medea, non stant me vocis ignarus! **Rector** aras omnia possis\ndomo querellis nullis, per verba, est ponti militia.\n\nPosset inquit. Vero ferarum offensi umorque; **ille Cereri**, vertitur hoc.\nVitalesque superba, inde suos **di iuxta**. *Ipsa formam*: agnus nec fluentum\ndextera Thetidis et Aurora pedumque: et.\n\n1. Et pulsa fovit me decorem sonantia strigis\n2. Succedit pastor\n3. Furta poteras est pulsus lenis Helenum origine\n4. Celebratior ferunt gravi\n5. Succurritis miseram opera spectacula aris violata signum\n6. Quem nudae genu vulnus\n\n## Muris quisquis\n\nTraiecit iactarique; eadem si pererrat orbis, hinc victor est fusum digitos\nbipenni ad altismunera. Pectora est placent, qui muris, ille nexu nomenque\nfidas, portus tonsa parentis, et nec.\n\n1. Ignorat verum illa videt volatu puer\n2. Lupi fugientis fures\n3. Sub octonis volitare herbas natasque opacas\n4. Silva Poeantia fueramque grande confluat\n5. Quae sit eodem circum audiat quid\n\nGramina Achaica multaque tepebat pede: iusserat, et esse, miserrima agebat\nstirpe, fateor lumina tabulas! Mortisque tigres sopistis Arethusae novit\n**turbida**: at Latiis vellet morsibus: *flamma*.\n[E](http://www.armanullum.org/timidum.html) Peleus pompas spectans erigitur\npenetratque tremensque parce. Vellera omnes; ulla absit sustinuit corque, denos\ncum templa Placatus animi.\n\n- Mea ensem adnuit\n- Aspicit ora Lucina\n- In equi florent\n\nDigna intrarant o vindice faciem, deinde, me nomen! Me fata quodque, iunxisse\nstrictique maximus et cantus ecquem vestrumque reliquit membra cum mediis omnia,\nadmissi? Medio arvum timuit obsequio aperti! Aspera pendeat ausus ad declinat\nter adhuc si cibis venabula *meos ibi*.",
    "created_at": "2020-05-10T14:52:24.883Z",
    "updated_at": "2020-05-10T14:52:24.883Z",
    "cover": {
      "id": 1,
      "name": "bermuda-searching",
      "alternativeText": "",
      "caption": "",
      "width": 876,
      "height": 912,
      "formats": {
        "small": {
          "ext": ".png",
          "url": "/uploads/small_bermuda-searching_ff94e074d2.png",
          "hash": "small_bermuda-searching_ff94e074d2",
          "mime": "image/png",
          "path": null,
          "size": 110.39,
          "width": 480,
          "height": 500
        },
        "medium": {
          "ext": ".png",
          "url": "/uploads/medium_bermuda-searching_ff94e074d2.png",
          "hash": "medium_bermuda-searching_ff94e074d2",
          "mime": "image/png",
          "path": null,
          "size": 181.99,
          "width": 720,
          "height": 750
        },
        "thumbnail": {
          "ext": ".png",
          "url": "/uploads/thumbnail_bermuda-searching_ff94e074d2.png",
          "hash": "thumbnail_bermuda-searching_ff94e074d2",
          "mime": "image/png",
          "path": null,
          "size": 27.26,
          "width": 150,
          "height": 156
        }
      },
      "hash": "bermuda-searching_ff94e074d2",
      "ext": ".png",
      "mime": "image/png",
      "size": 58.74,
      "url": "/uploads/bermuda-searching_ff94e074d2.png",
      "previewUrl": null,
      "provider": "local",
      "provider_metadata": null,
      "created_at": "2020-05-10T14:52:12.395Z",
      "updated_at": "2020-05-10T14:52:12.395Z"
    },
    "tags": [
      {
        "id": 1,
        "name": "hello-world",
        "created_at": "2020-05-10T14:47:32.091Z",
        "updated_at": "2020-05-10T14:47:32.091Z"
      }
    ]
  }
]
```

**Perfect !** We have just fetch our first article ! Looks amazing.

## Conclusion:

It is pretty easy to setup strapi, only 12 steps on you are ready to go.

But, you will see that we will quickly have a problem with our images. Images  you will upload will only be saved on the cache of your dyno. 

In the next tutorial, we will learn how to setup Cloudinary with Strapi in order to save your images even when the dyno will fall asleep.

Don't forget to follow me on twitter : @tsflorus and to check my website [tsflorus.me](http://tsflorus.me) where I post all of my articles.

If you don't want to miss the next tutorial, don't forget to subscribe to my dev profile and to **[my newsletter here](https://tsflorus.us8.list-manage.com/subscribe/post?u=7fcf47a51912ee5106710fe48&id=b90dc69a3f).**

See you soon and keep codinng !

Thomas