Our community is looking for talented writers who are passionate about our ecosystem (jamstack, open-source, javascript) and willing to share their knowledge/experiences through our Write for the community program.
There's a whole series in blog of tutorials on how to make blogs using Strapi with a lot of frontend frameworks: Gatsby, React, Next.js, Vue, Nuxt or Angular.
This time we are going to create a Gatsby blog using TypeScript, and adding one of coolest plugins in the ecosystem: gatsby-image.
Caveat emptor: this is a re write of the previous tutorial about creating a blog with STRAPI + Gatsby. So the design will be the same.
The goal here is to be able to create a simple static blog website using Strapi as the backend and Gatsby for the frontend, using TypeScript.
The source code is available on GitHub.
This tutorial uses Strapi v3.0.0-beta.20.3.
You need to have node v.12 installed and that's all.
Create a strapi-gatsby-typescript-blog
folder and get inside!
mkdir strapi-gatsby-typescript-blog && cd strapi-gatsby-typescript-blog
That's the easiest part, as since beta.9 Strapi has an excellent package create strapi-app that allows you to create a Strapi project in seconds without needing to install Strapi globally so let's try it out.
Note: for this tutorial, we will use yarn
as your package manager.
yarn create strapi-app backend --quickstart --no-run
.This single command line will create all you need for your back-end. Make sure to add the --no-run
flag as it will prevent your app from automatically starting the server because SPOILER ALERT: we need to install some awesome Strapi plugins.
Now that you know that we need to install some plugins to enhance your app, let's install one of our most popular ones: the graphql
plugin.
yarn strapi install graphql
Once the installation is completed, you can finally start your Strapi server strapi dev
and create your first Administrator.
Don't forget that Strapi is running on http://localhost:1337
Nice! Now that Strapi is ready, you are going to create your Gatsby application.
The easiest part has been completed, let's get our hands dirty developing our blog with Gatsby!
Gatsby setup
First of all, you'll need to install the Gatsby CLI
Install the Gatsby CLI by running the following command:
npm install -g gatsby-cli
Create a Gatsby frontend
project by running the following command:
gatsby new frontend https://github.com/resir014/gatsby-starter-typescript-plus
Once the installation is completed, you can start your front-end app to make sure everything went ok.
1cd frontend
2gatsby develop
Good start!
A little note about the starter: as you can see, we didn't use the default Gatsby starter repo, we used a TypeScript starter, so we don't have to add it ourselves ;)
We are not keeping the default Gatsby starter style but the one we used for every other tutorials of this series.
UIkit setup
We need to create a Seo
component that will allow us to add UIkit cdn and Staatliches font
components/Seo.tsx
(mind the file extension, TypeScript React/Gatsby files are .tsx) and add this code:1import React from 'react'
2import PropTypes from 'prop-types'
3import { Helmet } from 'react-helmet'
4import { useStaticQuery, StaticQuery, graphql } from 'gatsby'
5
6interface StaticQueryProps {
7 site: {
8 siteMetadata: {
9 title: string
10 description: string
11 author: string
12 keywords: string
13 }
14 }
15}
16
17interface Props {
18 readonly title?: string
19 readonly children?: React.ReactNode
20}
21
22const SEO: React.FC<Props> = ({ children }) => (
23 <StaticQuery
24 query={graphql`
25 query SeoQuery {
26 site {
27 siteMetadata {
28 title
29 description
30 }
31 }
32 }
33 `}
34 render={(data: StaticQueryProps) => (
35 <Helmet
36 htmlAttributes={{
37 lang: `en`
38 }}
39 title={data.site.siteMetadata.title}
40 titleTemplate={`%s | ${data.site.siteMetadata.title}`}
41 link={[
42 {
43 rel: 'stylesheet',
44 href: 'https://fonts.googleapis.com/css?family=Staatliches'
45 },
46 {
47 rel: 'stylesheet',
48 href: 'https://cdn.jsdelivr.net/npm/uikit@3.2.3/dist/css/uikit.min.css'
49 }
50 ]}
51 script={[
52 {
53 src: 'https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/js/uikit.min.js'
54 },
55 {
56 src: 'https://cdn.jsdelivr.net/npm/uikit@3.2.3/dist/js/uikit-icons.min.js'
57 },
58 {
59 src: 'https://cdnjs.cloudflare.com/ajax/libs/uikit/3.2.0/js/uikit.js'
60 }
61 ]}
62 meta={[
63 {
64 name: `description`,
65 content: data.site.siteMetadata.description
66 },
67 {
68 property: `og:title`,
69 content: data.site.siteMetadata.title
70 },
71 {
72 property: `og:description`,
73 content: data.site.siteMetadata.description
74 },
75 {
76 property: `og:type`,
77 content: `website`
78 },
79 {
80 name: `twitter:card`,
81 content: `summary`
82 },
83 {
84 name: `twitter:creator`,
85 content: 'kilinkis'
86 },
87 {
88 name: `twitter:title`,
89 content: data.site.siteMetadata.title
90 },
91 {
92 name: `twitter:description`,
93 content: data.site.siteMetadata.description
94 }
95 ]}
96 />
97 )}
98 />
99)
100
101export default SEO
Let's explain that code a little bit:
Here we are using the React Helmet library (fun fact: it was created by the NFL devs). It handles the <head>
component of our app. In this case, we import UIkit from a CDN, also the font and handle metadescriptions.
We also define two interfaces we need in order to use our components, these are StaticQueryProps
and Props
.
StaticQueryProps
describes the object returned in the query that fetches the site description.
Props
is very simple, it describes the kind of Props that the React Functional Component below expects.
We'll talk more about StaticQuery
later on when we fetch our articles :)
In order to have a simple but beautiful blog we're going to add some style:
src/styles/main.ts
file containing the following:1export default `
2 a {
3 text-decoration: none !important;
4 }
5
6 h1 {
7 font-family: Staatliches !important;
8 font-size: 120px !important;
9 }
10
11 #category {
12 font-family: Staatliches !important;
13 font-weight: 500 !important;
14 }
15
16 #title {
17 letter-spacing: 0.4px !important;
18 font-size: 22px !important;
19 font-size: 1.375rem !important;
20 line-height: 1.13636 !important;
21 }
22
23 #banner {
24 margin: 20px !important;
25 height: 800px !important;
26 }
27
28 #editor {
29 font-size: 16px !important;
30 font-size: 1rem !important;
31 line-height: 1.75 !important;
32 }
33
34 .uk-navbar-container {
35 background: #fff !important;
36 font-family: Staatliches !important;
37 }
38
39 img:hover {
40 opacity: 1 !important;
41 transition: opacity 0.25s cubic-bezier(0.39, 0.575, 0.565, 1) !important;
42 }
43 .banner-bg {
44 position: absolute !important;
45 width: calc(100% - 2.5rem) !important;
46 height: 800px !important;
47}
48`
We are not going to explain that CSS, but feel free to change anything as you need :)
Now we need to include this file in out layout wrapper in order to make it available to our app:
src/components/LayoutRoot.tsx
and add the import after Normalize, like so:import main from '../styles/main'
and finally, add our freshly imported main
CSS to the Global component:
<Global styles={() => css(normalize, main)} />
Nice! Let's continue.
Strapi Setup
To connect Gatsby to a new source of data, you have to develop a new source plugin. Fortunately, several source plugins already exist, so one of them could fill your needs.
In this example, we are using Strapi as the backend provider, so we need a source plugin for Strapi APIs. Good news: we built it for you!
gatsby-source-strapi
by running the following command:yarn add gatsby-source-strapi
This plugin needs to be configured.
gatsby-config.js
with the following code:1'use strict'
2
3require('dotenv').config({
4 path: `.env.${process.env.NODE_ENV}`
5})
6
7module.exports = {
8 siteMetadata: {
9 title: 'My super blog',
10 description: 'Gatsby blog with Strapi',
11 author: {
12 name: 'Strapi team',
13 url: 'https://strapi.io/'
14 }
15 },
16 plugins: [
17 {
18 resolve: 'gatsby-source-strapi',
19 options: {
20 apiURL: process.env.API_URL || 'http://localhost:1337',
21 collectionTypes: [
22 // List of the Content Types you want to be able to request from Gatsby.
23 'article',
24 'category'
25 ],
26 queryLimit: 1000
27 }
28 },
29 'gatsby-transformer-json',
30 {
31 resolve: 'gatsby-plugin-canonical-urls',
32 options: {
33 siteUrl: 'https://gatsby-starter-typescript-plus.netlify.com'
34 }
35 },
36 'gatsby-plugin-emotion',
37 'gatsby-plugin-typescript',
38 'gatsby-plugin-sharp',
39 'gatsby-transformer-sharp',
40 'gatsby-plugin-react-helmet'
41 ]
42}
As you can see at the top of that code, we are using environment variables for our API url. So, create a .env.development
file a the root of your frontend folder containing the following:
API_URL="http://localhost:1337"
Important note that we defined our API_URL
for the Strapi API: http://localhost:1337
without a trailing slash and that we plan to query content types article and category
Alright! Gatsby is now ready to fetch data from Strapi, but first, we need to create some data in Strapi!
Finally! We are now going to create the data structure of our article by creating an Article
content type.
Content-Types Builder
link in the sidebar.Create new collection type
and call it article
.Now you'll be asked to create all the fields for your collection-type:
title
with type Text (required)content
with type Rich Text (required)image
with type Media (Single image) and (required)published_at
with type date (required)Press Save! Here you go, your first content type has been created. Now you may want to create your first article, but we have one thing to do before that: Grant access to the article content type.
public
role.find
and findone
routes and save.Awesome! You should be ready to create your first article right now and fetch it on the GraphQL Playground.
Now, create your first article !
Here's an example:
Great! Now you may want to reach the moment when you can actually fetch your articles through the API!
Go to http://localhost:1337/articles.
Isn't that cool! You can also play with the GraphQL Playground.
You may want to assign a category to your article (news, trends, opinion). You are going to do this by creating another collection type in Strapi.
Create a new Collection Type, named category
, with a Text field named category and a Relation field, that has Many to One relationship.
Press save!
Category has many Articles
like below:Click on the Settings then Roles & Permission and click on the public
role. And check the category find
and findone
routes and save.
Now you'll be able to select a category for your article in the right sidebox.
Now that we are good with Strapi let's work on the frontend part!
Before we can dive in, we have to clean the default Gatsby architecture by removing useless files with the following command:
rm src/pages/page.tsx src/pages/page-2.tsx
Since we are using TypeScript in this project, we are writting type safe code, and for that we are using Interfaces in most cases. To avoid duplicated code, we can declare interfaces in the typings.d.ts
file.
In this case, lets declare our Article interface so we can use it across our app.
typings.d.ts
file:1interface Article {
2 node: {
3 id: number
4 strapiId: string
5 image: {
6 childImageSharp: {
7 fixed: FixedObject
8 fluid: FluidObject
9 }
10 }
11 category: {
12 name: string
13 }
14 title: string
15 content: string
16 }
17}
Now we need to update the layout/index.tsx
file. Replace its content with the following code:
1import * as React from 'react'
2import { StaticQuery, graphql } from 'gatsby'
3
4import 'modern-normalize'
5import '../styles/normalize'
6
7import LayoutRoot from '../components/LayoutRoot'
8
9import ArticlesComponent from '../components/Articles'
10
11interface StaticQueryProps {
12 site: {
13 siteMetadata: {
14 title: string
15 description: string
16 keywords: string
17 }
18 }
19 allStrapiArticle: {
20 edges: Article[]
21 }
22}
23
24interface Props {
25 readonly title?: string
26 readonly children: React.ReactNode
27}
28
29const IndexLayout: React.FC<Props> = ({ children }) => (
30 <StaticQuery
31 query={graphql`
32 query IndexLayoutQuery {
33 site {
34 siteMetadata {
35 title
36 description
37 }
38 }
39 allStrapiArticle {
40 edges {
41 node {
42 strapiId
43 title
44 category {
45 name
46 }
47 image {
48 childImageSharp {
49 fluid(maxWidth: 595, quality: 100) {
50 ...GatsbyImageSharpFluid
51 ...GatsbyImageSharpFluidLimitPresentationSize
52 }
53 }
54 }
55 }
56 }
57 }
58 }
59 `}
60 render={(data: StaticQueryProps) => (
61 <LayoutRoot>
62 <div className="uk-section">
63 <div className="uk-container uk-container-large">
64 <h1>Strapi blog</h1>
65 <ArticlesComponent articles={data.allStrapiArticle.edges} />
66 </div>
67 </div>
68 </LayoutRoot>
69 )}
70 />
71)
72
73export default IndexLayout
What is going on here ? Let me explain
Gatsby v2 introduces StaticQuery
, a new API that allows components to retrieve data via a GraphQL query
1allStrapiArticle {
2 edges {
3 node {
4 strapiId
5 title
6 category {
7 name
8 }
9 image {
10 childImageSharp {
11 fluid(maxWidth: 595, quality: 100) {
12 ...GatsbyImageSharpFluid
13 ...GatsbyImageSharpFluidLimitPresentationSize
14 }
15 }
16 }
17 }
18 }
19}
This one will fetch all your articles from Strapi. Here, for each article we are querying: the id, title, category and image. The image object, as you can see, it's a little complex. This is because we are using gatsby-image here. This is one of the most popular plugins in Gatsby, mainly because it fixes these common problems virtually for free (taken from their docs):
I use it in every Gatsby project, I just think it helps in our endeavour of making the web a better place. You can read more about it and its API on the offical docs.
Then StaticQuery
render your html with the fetched data:
1render={(data: StaticQueryProps) => (
2 <LayoutRoot>
3 <div className="uk-section">
4 <div className="uk-container uk-container-large">
5 <h1>Strapi blog</h1>
6 <ArticlesComponent articles={data.allStrapiArticle.edges} />
7 </div>
8 </div>
9 </LayoutRoot>
10)}
Now we need to update the components/Header.tsx
file. Replace its content with the following code:
1import * as React from 'react'
2import { Link, StaticQuery, graphql } from 'gatsby'
3
4interface categoryInterface {
5 node: {
6 strapiId: number
7 name: string
8 }
9}
10
11interface HeaderProps {
12 title?: string
13}
14
15const Header: React.FC<HeaderProps> = ({ title }) => (
16 <div>
17 <div>
18 <nav className="uk-navbar-container" data-uk-navbar>
19 <div className="uk-navbar-left">
20 <ul className="uk-navbar-nav">
21 <li>
22 <Link to="/">Strapi Blog</Link>
23 </li>
24 </ul>
25 </div>
26
27 <div className="uk-navbar-right">
28 <ul className="uk-navbar-nav">
29 <StaticQuery
30 query={graphql`
31 query {
32 allStrapiCategory {
33 edges {
34 node {
35 strapiId
36 name
37 }
38 }
39 }
40 }
41 `}
42 render={data =>
43 data.allStrapiCategory.edges.map((category: categoryInterface, i: number) => {
44 return (
45 <li key={category.node.strapiId}>
46 <Link to={`/category/${category.node.strapiId}`}>{category.node.name}</Link>
47 </li>
48 )
49 })
50 }
51 />
52 </ul>
53 </div>
54 </nav>
55 </div>
56 </div>
57)
58
59export default Header
There's not so much to explain here, but basically we add the two new Interfaces we need: categoryInterface
and HeaderProps
.
Then StaticQuery
gets all the categories we defined in our backend.
1allStrapiCategory {
2 edges {
3 node {
4 strapiId
5 name
6 }
7 }
8}
And loops through them to create the Catergory navegation.
1render={data =>
2 data.allStrapiCategory.edges.map((category: categoryInterface, i: number) => {
3 return (
4 <li key={category.node.strapiId}>
5 <Link to={`/category/${category.node.strapiId}`}>{category.node.name}</Link>
6 </li>
7 )
8 })
9}
Now we need to use this component in your Layout
component.
Header
component by pasting the following code inside your components/LayoutRoot.tsx
file:1import * as React from 'react'
2import Seo from './Seo'
3import Header from './Header'
4import { Global, css } from '@emotion/core'
5import normalize from '../styles/normalize'
6import main from '../styles/main'
7
8interface LayoutRootProps {
9 className?: string
10}
11
12const LayoutRoot: React.FC<LayoutRootProps> = ({ children, className }) => (
13 <>
14 <Seo />
15 <Global styles={() => css(normalize, main)} />
16 <Header />
17 <main>{children}</main>
18 </>
19)
20
21export default LayoutRoot
Also, we need to update the content of our index page, editing the content of ./pages.index.tsx
. Replace its content with this:
1import * as React from 'react'
2
3import Page from '../components/Page'
4import IndexLayout from '../layouts'
5
6const IndexPage = () => (
7 <IndexLayout>
8 <Page></Page>
9 </IndexLayout>
10)
11
12export default IndexPage
At this point we can show the navigation header and the empty landing page, but wait... not so fast, if we try to compile the project now, it will fail because our gatsby-node file
is outdated. We'll add the correct code there soon.
Note: The current code is not designed to display a lot of categories as one would encounter in a typical blog.
Great! But we still need to create some extra components we added in our main layout file.
components/articles.tsx
containing the following code:1import React from 'react'
2import Card from './Card'
3
4interface ArticlesProps {
5 articles: Article[]
6}
7
8const Articles: React.FC<ArticlesProps> = ({ articles }) => {
9 const leftArticlesCount = Math.ceil(articles.length / 5)
10 const leftArticles = articles.slice(0, leftArticlesCount)
11 const rightArticles = articles.slice(leftArticlesCount, articles.length)
12
13 return (
14 <div>
15 <div className="uk-child-width-1-2" data-uk-grid>
16 <div>
17 {leftArticles.map(article => {
18 return <Card article={article} key={`article__${article.node.id}`} />
19 })}
20 </div>
21 <div>
22 <div className="uk-child-width-1-2@m uk-grid-match" data-uk-grid>
23 {rightArticles.map(article => {
24 return <Card article={article} key={`article__${article.node.id}`} />
25 })}
26 </div>
27 </div>
28 </div>
29 </div>
30 )
31}
32
33export default Articles
Here we are splitting our articles because we want to display some of them on the left side of the blog making them bigger and some on the right making them smaller. It's just a design thing.
Again, we are using another component: Card
. Since Components are the building blocks of any React application, this is why you will find so many of them.
The benefit to this approach is that you end up doing less duplicate work by managing the components rather than managing duplicate content across different pages. This concept has become a real success and you are going to use it too!
components/card.js
file containing the following code:1import React from 'react'
2import { Link } from 'gatsby'
3import Img, { FixedObject } from 'gatsby-image'
4
5interface ArticleProps {
6 article: Article
7}
8
9const Card: React.FC<ArticleProps> = ({ article }) => {
10 return (
11 <Link to={`/article/${article.node.strapiId}`} className="uk-link-reset">
12 <div className="uk-card uk-card-muted">
13 <div className="uk-card-media-top">
14 <Img fluid={article.node.image.childImageSharp.fluid} />
15 </div>
16 <div className="uk-card-body">
17 <p id="category" className="uk-text-uppercase">
18 {article.node.category.name}
19 </p>
20 <p id="title" className="uk-text-large">
21 {article.node.title}
22 </p>
23 </div>
24 </div>
25 </Link>
26 )
27}
28
29export default Card
Awesome! Now let's updade the gatsby.node.js
file to create the article and category pages and finish the tutorial :)
How can we create a page for each one of your article now? We'll need to use the createPages
API. It will be called once the data layer is bootstrapped to let plugins create pages from data.
gatsby.node.js
file:1'use strict'
2
3const path = require('path')
4
5exports.createPages = async ({ graphql, actions }) => {
6 const { createPage } = actions
7 const result = await graphql(
8 `
9 {
10 articles: allStrapiArticle {
11 edges {
12 node {
13 strapiId
14 }
15 }
16 }
17 categories: allStrapiCategory {
18 edges {
19 node {
20 strapiId
21 }
22 }
23 }
24 }
25 `
26 )
27
28 if (result.errors) {
29 throw result.errors
30 }
31
32 // Create blog articles pages.
33 const articles = result.data.articles.edges
34 const categories = result.data.categories.edges
35
36 articles.forEach((article, index) => {
37 createPage({
38 path: `/article/${article.node.strapiId}`,
39 component: require.resolve('./src/templates/article.tsx'),
40 context: {
41 id: article.node.strapiId
42 }
43 })
44 })
45
46 categories.forEach((category, index) => {
47 createPage({
48 path: `/category/${category.node.strapiId}`,
49 component: require.resolve('./src/templates/category.tsx'),
50 context: {
51 id: category.node.strapiId
52 }
53 })
54 })
55}
We are fetching all your article and category ids in order to generate pages for each one of them
It means that if you have 4 articles it will create 4 pages depending on the path you give, here it's path: /article/${article.node.strapiId}
:
1/article/1
2/article/2
3/article/3
4/article/4
Just to keep it short, in that same step we added the node loop to create the category
page. We'll work on that template soon.
Before going further you'll need to install two packages: one to display your content as Markdown and Moment
react-markdown
and react-moment
by running the following command:yarn add react-markdown react-moment moment
Now we need to create the page that will display each one of your article, you can see inside gatsby.node.js
that here it's component: require.resolve("./src/templates/article.tsx")
src/templates/article.tsx
file containing the following:1import React from 'react'
2import { graphql } from 'gatsby'
3import Img, { FixedObject } from 'gatsby-image'
4
5import ReactMarkdown from 'react-markdown'
6
7import LayoutRoot from '../components/LayoutRoot'
8
9interface ArticleProps {
10 data: {
11 strapiArticle: {
12 image: {
13 childImageSharp: {
14 fixed: FixedObject
15 }
16 }
17 title: string
18 content: string
19 }
20 }
21}
22
23export const query = graphql`
24 query ArticleQuery($id: Int!) {
25 strapiArticle(strapiId: { eq: $id }) {
26 strapiId
27 title
28 content
29 published_at
30 image {
31 childImageSharp {
32 fixed(width: 660) {
33 ...GatsbyImageSharpFixed
34 }
35 }
36 }
37 }
38 }
39`
40
41const Article: React.FC<ArticleProps> = ({ data }) => {
42 const article = data.strapiArticle
43 return (
44 <LayoutRoot>
45 <div>
46 <div
47 id="banner"
48 className="uk-height-medium uk-flex uk-flex-center uk-flex-middle uk-background-cover uk-light uk-padding uk-margin"
49 >
50 <Img className="banner-bg" fixed={article.image.childImageSharp.fixed} />
51 <h1 className="uk-position-z-index">{article.title}</h1>
52 </div>
53
54 <div className="uk-section">
55 <div className="uk-container uk-container-small">
56 <ReactMarkdown source={article.content} />
57 </div>
58 </div>
59 </div>
60 </LayoutRoot>
61 )
62}
63
64export default Article
Remember we already added the category
code in our gatsby.node.js
file already? Okay, now we are going to use that.
We need to create the category
template, as required here component: require.resolve("./src/templates/category.tsx")
src/templates/category.tsx
file containing the following code:1import React from 'react'
2import { graphql } from 'gatsby'
3
4import LayoutRoot from '../components/LayoutRoot'
5import ArticlesComponent from '../components/articles'
6
7interface CategoryProps {
8 data: {
9 articles: {
10 edges: Article[]
11 }
12 category: {
13 name: string
14 }
15 }
16}
17
18export const query = graphql`
19 query Category($id: Int!) {
20 articles: allStrapiArticle(filter: { category: { id: { eq: $id } } }) {
21 edges {
22 node {
23 strapiId
24 title
25 category {
26 name
27 }
28 image {
29 childImageSharp {
30 fluid(maxWidth: 595, quality: 100) {
31 ...GatsbyImageSharpFluid
32 ...GatsbyImageSharpFluidLimitPresentationSize
33 }
34 }
35 }
36 }
37 }
38 }
39 category: strapiCategory(strapiId: { eq: $id }) {
40 name
41 }
42 }
43`
44
45const Category: React.FC<CategoryProps> = ({ data }) => {
46 const articles = data.articles.edges
47 const category = data.category.name
48
49 return (
50 <LayoutRoot>
51 <div className="uk-section">
52 <div className="uk-container uk-container-large">
53 <h1>{category}</h1>
54 <ArticlesComponent articles={articles} />
55 </div>
56 </div>
57 </LayoutRoot>
58 )
59}
60
61export default Category
You can see that we are using the ArticlesComponent
again! In fact we are displaying articles the same we as in the index, this is why we created a component, in order to not duplicate code ;)
gatsby.node.js
file)Huge congrats, you successfully achieved this tutorial. I hope you enjoyed it!
Still hungry?
Feel free to add additional features, adapt this project to your own needs, and give your feedback in the comment section below.
If you want to deploy your application, check our documentation.
Contribute and collaborate on educational content for the Strapi Community https://strapi.io/write-for-the-community
Can't wait to see your contribution!
One last thing, we are trying to make the best possible tutorials for you, help us in this mission by answering this short survey https://strapisolutions.typeform.com/to/bwXvhA?channel=xxxxx
Please note: Since we initially published this blog, we released new versions of Strapi and tutorials may be outdated. Sorry for the inconvenience if it's the case, and please help us by reporting it here.
Get started with Strapi by creating a project, using a starter or trying our instant live demo. Also, consult our forum if you have any questions. We will be there to help you.
See you soon!