Build an instagram clone with react, next 13 and firebase part 1: Setup
Tags: firebase, nextjs, typescript
Published: 2023-05-10 21:38:28

## Introduction
Good day everyone! Today we are gonna start working on a new tutorial series on firebase.

In this series we will use firebase and nextjs 13 to build a clone of instagram, complete with the following functionality:

* Google and email sign in (with Firebase auth)
* CRUD functionality for posts and comments (with Firebase firestore)
* Hosting of our own images and gifs (with Firebase storage)
* Simple automatic banning of undesired content (with Firebase functions)

I'll even throw in hosting in vercel (NextJs is easier to host in vercel than in firebase)

Hopefully this all sounds exiting, this first part of our project will focus on setting up firebase, and our NextJs project.

* Little shameful advertising time! I actually will upload this series in my own personal website over at [daniel-armenta.com](https://daniel-armenta.com/blog). I will post parts there first, so consider checking it out and letting me know when you inevitably find bugs in my website.

## Create a NextJs 13 project

To begin, let's create a new project with NextJs version 13.
To do this, run the following command inside your projects directory:
```cmd
npx create-next-app@latest --ts instagram-tutorial
```

For this project I will be using typescript, so I added the --ts flag, but I will also share the javascript code here for you to use if you don't like typescript, so feel free to remove that flag.

Running this command will give you the following output if you haven't installed create-next-app:
```cmd
Need to install the following packages:
  create-next-app@13.3.2
Ok to proceed? (y)
```
Go ahead and press enter and now you will be given a few options, I'll show what I set up, but if you have some different preference, feel free to change your answers.

1. Would you like to use ESLint with this project? ... **No** / Yes
2. Would you like to use Tailwind CSS with this project? ... **No** / Yes
3. Would you like to use `src/` directory with this project? ... No / **Yes**
4. Would you like to use experimental `app/` directory with this project? ... No / **Yes**
5. What import alias would you like configured? ... ***@/****


Warning! keep in mind that if you decide not to use the _experimental app directory_, your project and mine will look very different

After running this command and waiting a bit, you should see a message like the following:
```cmd
Success! Created instagram-tutorial at D:\Users\h8moss\projects\instagram-tutorial
```

Go ahead and open the project in your favorite code editor and run `npm run dev` to start debugging on [localhost:3000](http://localhost:3000)

Open localhost:3000 and you should see something like this:
![Screenshot of initial project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ua4wbiuvwsa2hi7dcqyu.png)

Now over at our code editor, we can see our project looks like this:

![File tree](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i3lo3jvxy4kdrhs9gim3.png)

The `.next`, `.vscode` and `node_modules` folders can be ignored. We can also ignore `.gitignore`, `README.md`, `next.env.d.ts`, `package.json` and `package-lock.json`

The `public` folder includes static files for our app, like the logo or a `robots.txt` file if we wanted.
The `next.config.js` file contains configuration for our nextJs project, we can leave it be for now.
`tsconfig.json` has simple typescript configuration for the project.

Finally, the `src` directory will contain all of our code. The `app` directory inside it determines the routing of our app.

We can see there is a `page.tsx` and a `layout.tsx` at the root of our app, there is also a `route.ts` at `/api/hello`. If you are new to nextjs 13, I will explain what all of these routes are shortly.

Inside the app directory, there are special files identified by their names, we currently have the following:
* The `page.tsx` file, which defines a page inside of our app.
* The `layout.tsx` file, which defines code that every child page will have.
* The `route.ts` file which defines an API handler route.

There are also other special files we will come to know later down the tutorial series.

For now, the `route.ts` file inside /api/hello folder means that `localhost:3000/api/hello` works as an API directory, we don't actually need this behaviour, so let's remove the entire `/api` folder.

We also have a `layout.tsx` file at the root of our app folder, this means that every route will share the code inside this layout file. The layout file looks like this:
```tsx
import './globals.css'
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] })

export const metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  )
}
```
This file first imports the `globals.css` file, which contains our general css.
Then imports and defines `Inter` which is the font used in the example.
Next we export a metadata object, which has `head` related information like the title and description.
It finally, exports a component, which just defines an html tag with a body and the {children} property, which will be replaced with the actual code of our pages.

All of this is pretty basic stuff, so we won't change much, let's just change the metadata object to align more with what we are trying to make:

```ts
export const metadata = {
  title: "Instagram clone",
  description:
    "A simple website for a tutorial, showcasing the capabilities of Nextjs and firebase",
};
```

Let's also go over to `globals.css` and replace all of the default styles with something much more simple:
```css
* {
  padding: 0;
  margin: 0;
}

html,
body {
  max-width: 100vw;
  overflow-x: hidden;
}

a {
  color: inherit;
}
```
If we need more global styles, we can add them later.


This is not a CSS tutorial, so the styles we will be using will not be explained and they will be very rudamentary, I will give you the styles but I won't explain them, so feel free to experiment with your own styles.

The next file we have to take a look at is the `page.tsx` file.

This file, as it is in the root of our app directory, defines the root of our website, it currently has a lot of code for the website we saw earlier, so let's replace it with something far more simple:
```tsx
const Root = () => {
  return (
    <div>
      <h1>Hello world</h1>
      <p>Welcome to NextJs 13</p>
    </div>
  );
};

export default Root;
```
We can also delete the `page.module.css` file for now, as we don't have any page specific styles. 


Do keep in mind we will probably create it again later, so you can just delete the contents if you want.

## Setting up a firebase project

Now that we have a basic NextJs project, let's go ahead and create a firebase project.

To do this, I took the liberty of making a [scribe document](https://scribehow.com/shared/Firebase_setup__5Hvl-ZglTIueeTuwnP1gTw)

If you can't see, or don't want to use the scribe, the actual steps are as follows:

1. Go to the [firebase console](https://console.firebase.google.com)
2. Sign in or create an account
3. Click on "Add project"
4. Give the project a name
5. Select continue until asked about google analytics account
6. Select default account.
7. Select continue again
8. Wait for the project to be created.
9. Press continue

Now that we have a firebase project, we are gonna set up the following things:

1. Authentication
2. Database
3. Storage

So first, over to the left there are some menus, under the build menu we will find the `authentication` option, go ahead and click it.

### Setting up authentication

You know what to do, let's go over to the authentication page:
![Navigating to authentication menu](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8rm5y5o3m8xjfyt0eg5j.gif)

Now that we are on the authentication page, let's click on the "get started" button, which after a while will take you to the following page:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u6fj8qyyoie5i3t8gy2k.png)

This page has a list of all the different sign in options a user can have. There are 3 categories: 

1. Native providers: The most basic providers, like email and password or phone authentication
2. Additional providers: Providers that use some different website to sign in, like twitter or google.
3. Custom providers: These providers allow you to use some special features of authentication, but have different pricing, [you can read more here](https://firebase.google.com/docs/auth?hl=en&authuser=0#identity-platform)

For our project, we only want the email/password provider and the google provider 

Let's first register the email provider, which requires the least configuration of all, go ahead and click on the `email/password` button.

You will see 2 options, the first enables normal email/password sign in, the second enables password-less sign in. We only want email/password sign in, so let's only enable that one

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/20bjfwsitzw46s27qlvk.gif)

Now it is possible to sign in to our website using an email and a password, let's continue by activating google sign in, which requires a "public-facing name" and a "support email".

So go click on the new "add new provider" button and add the google provider:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yjmabo2dznh961p5ngij.gif)

With this, we now have activated the possibility of signing in with either google or a username and password.

#### Challenge
With the google and email sign in we have more than enough providers, but would you like to add a different provider into your app? You could try to add a facebook sign in option or a twitter sign in option, both of which require a developer account with either facebook or twitter, which I don't have by principle, but nothing is stopping you from making them.

Here are some resources:
* [Firebase authentication docs](https://firebase.google.com/docs/auth/?hl=en&authuser=0)
* [Firebase facebook authentication tutorial](https://firebase.google.com/docs/auth/web/facebook-login?authuser=0)
* [Firebase twitter authentication tutorial](https://firebase.google.com/docs/auth/web/twitter-login?authuser=0)

### Setting up a database in firebase

Firebase also comes with two different databases we could use, the realtime database and the firestore database. We are gonna be using the firestore database for this project.

Go ahead and click on the firestore button on your build menu:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/b6tq77qfga5p9ymp3fqs.gif)

You should see a button to create a database, go ahead and click it, you will be asked 2 questions.

The first question asks about "production" vs "test" mode, this sets the rules for accessing the database, production mode defaults all operations to false, so you have to manually set rules while test mode sets them to true for a few days and changes them to false later.

We are gonna write our own rules later down the line, but for now, pick test mode.

The second question asks you where should the database be set up, for most projects you are gonna want either nam5 (US) or eur3 (Europe) depending on when you live. I live in Mexico, so I picked the US as that is closer.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oriax5fxagfv4xoscwbk.gif)

We have now created a working database, from this page we can view and edit the database's values, we will come back to this page in the firestore chapter, but for now, let's setup the storage system.

### Setting up storage

One last time, go over to the menu, this time click on storage:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixvsvzd7az2l8y61go00.gif)

You will be asked the same questions as when setting up firestore, but this time you won't be able to change the region as both firestore and storage must use the same region.

Go ahead and put the same values in.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/leznllgr7gm1if30jvvb.gif)

With that, our firebase storage should be working, we could start uploading stuff to it right now.

## Adding Firebase to our NextJS project

Now that we have created a firebase repository, we should try to add firebase to our NextJS project, to do that, let's install the firebase dependency:

```bash
npm install firebase
```

In order to use firebase, we need some information about our firebase project, this information is private and so we are gonna put it inside of a `.env.local` file. NextJS automatically reads any `.env.local` files in our repository and sets them as the keys of the `process.env` object.

Note that, in reality, the data we are gonna store is not so sensitive that we need to use a `.env.local` file to hide it. Still, it is a good idea to do so, just in case.

So create a `.env.local` file at the root of the project And fill it with the following:
```env
NEXT_PUBLIC_FIREBASE_API_KEY=...
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=...
NEXT_PUBLIC_FIREBASE_PROJECT_ID=...
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=...
NEXT_PUBLIC_FIREBASE_MESSAGE_SENDER_ID=...
NEXT_PUBLIC_FIREBASE_APP_ID=...
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=...
```

Make sure to add the `NEXT_PUBLIC` prefix, as it will allow us to read these variables from the client

Also remember to add the file into your `.gitignore` file if you are using git. If you want, I recommend creating a `.env.example` file for keeping example data to describe what the actual `.env.local` file has.

I'll explain in a second where we can find all this information, but first, let's put this information to use in our project.

Inside any folder where you want to keep your utility code, create a firebase file to put all of our firebase SDK related code

Personally, I like to create a `src/common/services/firebase` folder, inside of which I make a single file for each of the SDKs we are gonna use (for now only the main firebase SDK, but we will add more) and then a single `index.ts` file that imports all of them and exports them, so we can import directly from the folder.

Inside this file, we are gonna initialize the firebase `app` SDK, which will be required by all other firebase SDKs. 

```ts
import { initializeApp } from 'firebase/app';

const firebaseConfig = {
};

const app = initializeApp(firebaseConfig);
export default app;
```

Now, the `firebaseConfig` object is the one that will take all of our variables, so let's go ahead and fill our object:

```ts
const firebaseConfig = {
  apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
  authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
  projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
  storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
  messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
  appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
  measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
};
```

Great! Now, let's go over to the firebase console to get our data for our `.env` file.

First, go over to the firebase console menu and click on "Project overview"

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l3xiydz0reogb24xhd6l.gif)

Here we can see information about our project, including all of the apps that use our firebase project. 

We are gonna add a new web app, So click on the web simbol, from there, give your app a name.

You should now be able to see the data that we need to add to our `.env` file

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/14hsfk4duqorvo4uy5rb.gif)

Go ahead and copy that information over to your `.env` file, that should be enought to initialize firebase.

## Conclusion

And we are done! I know that was a lot of setup to end up barely writing any code, but the good news is that we are done setting up and we can now focus on writing code.

Next part in the series will focus on using all of the auth setup we did to create a simple sign in page and display the username of whoever is signed in.