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
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, 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 :
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 and here is what you should see :
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
Click on Content-Types Builder
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.
We are asked to select the different fields of this CT.
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:
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
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. 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.
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.
Click on the right add-on then select your plan. For this tutorial we will go one a Hobby Dev plan.
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.
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.
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 :
{
"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
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
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:
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
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
git init
3 - Set the remote branch for our app (here, tsflorus-strapi-tutorial has to be replaced with your heroku app's name)
heroku git:remote -a tsflorus-strapi-tutorial
4 - Add all of our changes
git add .
5 - Make a commit message
git commit -m "Initialize my Strapi app"
6 - Then, push to the master branch
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 !
We will now need to recreate an admin user. To do that, go on 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.
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:
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
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
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.
We will also need to set this find and findone permissions for the Users-Permissions on the bottom of the page
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 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
[
{
"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 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.
See you soon and keep codinng !
Thomas
Top comments (4)
Hi, i enjoyed your post and i have registerd to your newsletter, when will other parts come out?
I did all of them. But I also have a react app and It can use API locally but I want to deploy it in the same directory. How I should do it?
What app are we going to build?
We are going to build a simple blog for a company website