Deploy Fullstack App and Create CI/CD

  1. GitHub Repository Link

  2. Create an Account on Render


INTRO

In this article, I’m going to show you how to deploy a full-stack application from start to finish, including how to set up a CI/CD pipeline to make deployments easier. By the end of this article, you’ll have your app live and ready to use, and future updates will be automatically deployed! S0, Let’s get started.


STEP 1: Clean Up Console Logs

Before we deploy, let’s start by cleaning up our code. The first step is to remove all console.log statements from both the frontend and backend directories. This is crucial for keeping your production code clean and optimized.

Go through your files, and look for console.log statements in both the client and server code. Remove them one by one. You can also use a text editor’s search function (cmd + shift + f) on mac to find all instances of console.log and delete them.


STEP 2: Move some Backend Files to Root

Next, we need to bring four important files from the backend into the root directory. These are:

- `package.json`
- `package-lock.json`
- `.gitignore`
- `.env`

When deploying a full-stack application, we want to simplify the structure so that deployment services (like Render) can easily detect both the frontend and backend in one project. Having these files in the root ensures that everything is set up in one place and makes deployment smoother.


STEP 3: Modify server.js to Serve Frontend Files

Now, let’s modify our server.js file to handle the frontend build files.

We’re adding the following lines to server.js to tell the server to serve the static files of the frontend from the dist folder.

const path = require("path");

// Paste below code before the routes
app.use(express.static(path.join(__dirname, "../client/dist")));

app.get("*", (_, res) => {
  res.sendFile(path.resolve(__dirname, "../client/dist/index.html"));
});

This code ensures our Express server serves the frontend build files from the dist folder.

In a full-stack application, the backend needs to serve the frontend when deployed. Vite, which we use for the frontend, compiles everything into a dist folder. We’re telling the server to serve that dist folder so users can see the React frontend.

app.use(express.static(path.join(__dirname, "../client/dist"))): This tells the server to treat the dist folder as static, so it can serve the compiled HTML, CSS, and JS files. app.get("*", (_, res) => { res.sendFile(path.resolve(__dirname, "../client/dist/index.html")); }): This ensures that for any route in the frontend (e.g., /about, /contact), the server serves index.html. This is essential for single-page applications (SPAs).


STEP 4: Update package.json Scripts

The next step is to update the scripts in the root package.json file. Add the following lines:

"start": "node server/server.js",
"dev": "nodemon server/server.js",
"build": "npm install && npm install --prefix client && npm run build --prefix client",

These scripts will allow us to start, develop, and build our application efficiently.

  • "start": This script starts the server using Node.js, which is used when the app is deployed.
  • "dev": This script uses nodemon, a tool that restarts the server automatically when you make changes during development.
  • "build": This script installs dependencies for both the backend and frontend, and builds the frontend using Vite.

STEP 5: Build the Frontend

Let’s now build the frontend using Vite. Run the following command inside the frontend directory. So navigate to the client folder and Run the command:

cd client
npm run build

When using Vite for the frontend, the build command generates optimized production-ready files in a dist folder. These files are what will be served by the backend. The dist folder contains everything your app needs for production.


Create a GitHub Repository

Now, we need to upload our code to GitHub. If you don’t have a repository yet, create one and push your code. This will make it easy to integrate with Render for deployment.

GitHub serves as our version control system and makes it easier to collaborate. Also, Render will pull the code directly from GitHub when deploying the application.

Create a new repository on GitHub and follow the instructions to push your code there. Make sure to include the .gitignore file so that unnecessary files aren’t uploaded.

  1. Go to GitHub and log in.
  2. In the top-right corner, click the + icon and select New repository.
  3. Give your repository a name (e.g., my-project).
  4. Choose the repository as Public or Private based on your preference.
  5. Click on Create repository.

Initialize a Local Git Repository

Open your terminal, navigate to the project folder, and initialize the local repository:

cd /path/to/your/project
git init

Add Files to the Repository: Add your project files to the Git staging area:

git add .

Select the Branch:

git branch -M main 

git push -u origin main

Commit Your Changes: Commit the files you’ve added:

git commit -m "Initial commit"

Connect Your Local Repository to GitHub: Copy the HTTPS URL of the repository from GitHub. Then, link your local repository to the GitHub repository:

git remote add origin https://github.com/your-username/my-project.git

Push Your Code to GitHub:

git push -u origin main

Note: If your default branch is master, use master instead of main.

Your code is now pushed to GitHub! You can visit the repository on GitHub to verify that everything is uploaded.


STEP 7: Deploy on Render

Head over to Render.com, create an account if you don’t have one, and link your GitHub repository. Render will automatically detect your project settings. Select the appropriate branch, and we’re good to go. Add script in build and start section.

Build: npm run build

Start: npm run start

Go to Render, create an account, and choose “Create New” > “Web Service.” Connect your GitHub account, select your repository, and follow the prompts.


STEP 8: Add Environment Variables on Render

Once your project is linked, navigate to the “Environment” section in Render’s dashboard and add all necessary environment variables, such as our database credentials, API keys, etc. Like add all of the variables that we have in the env file.

On the Render dashboard, go to the environment settings and add your variables. These should match the ones you used in your .env file locally.

Now for the client url, for now, let’s leave it to localhost:5173. We will change this env variable, because it will not be the local host but the URL render will give us for our service. But for now, leave it to localhost


STEP 9: Deploy Your Project

Now, hit “Deploy” and wait for the build process to complete.

Render will now build and deploy both the backend and frontend. It may take a few minutes, but once it’s done, your project will be live.

You’ll see a live URL once the deployment is successful.


STEP 10: Update Frontend URLs

Once the project is deployed, we will get the application URL right. So now we, make sure to update any hardcoded localhost URLs in the frontend directory with the live URL that Render provided us.

We’re replacing any hardcoded localhost URLs in the frontend with the live URL from Render.

Search through your frontend code for localhost:3000 and replace it with the Render-provided URL.

Also, make sure to change Client URL in environment setting of render.


STEP 11: Test the Application

Now that everything is deployed, it’s time to test the application. Make sure everything works as expected, both on the frontend and backend.

It’s important to ensure that all features, API calls, and routes work as expected after deployment.

Visit the live URL and navigate through your app and test the functionality and check console for any error.


STEP 12: Setup CI/CD Pipeline

Let’s set up a CI/CD pipeline so that future changes are automatically deployed. Add the following configuration to your .github/workflows/ci-cd.yaml file.

name: CI/CD Pipeline

on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [14.x, 16.x]

    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v2
        with:
          node-version: ${{ matrix.node-version }}

      - name: Install dependencies (client)
        run: |
          cd client
          npm install          

      - name: Install dependencies (server)
        run: |
          cd server
          npm install          

      - name: Build client
        run: |
          cd client
          npm run build          

      - name: Deploy to Render
        env:
          RENDER_API_KEY: ${{ secrets.RENDER_DEPLOY_HOOK }}
        run: |
          curl -X POST \
          -H "Authorization: Bearer $RENDER_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{"serviceId": "srv-YOUR_SERVICE_ID"}' \
          https://api.render.com/v1/services/srv-YOUR_SERVICE_ID/deploys          

CI/CD (Continuous Integration and Continuous Deployment) pipelines help automate the deployment process. This way, every change pushed to GitHub will automatically be built and deployed, saving you time and reducing errors.

This ensures that every push to the main branch will trigger a new deployment.

The serviceId here is specific to your Render service, and you can find it in your Render dashboard[in you project’s service URL]. You’ll need to set up the RENDER_DEPLOY_HOOK in GitHub Secrets to keep your API key secure too.


STEP 13: Get Render Deploy Hook and Service ID

Finally, we need to get the deploy hook and service ID from the Render dashboard. This allows our CI/CD pipeline to trigger automatic deployments.

  • The deploy hook can be found in the settings of your Render’s project service.
  • Navigate to the settings then scroll down until you find Deploy Hook Section, then copy the render hook and paste it into our CI/CD Pipeline.
  • And as for the service ID it is present in the URL of your project dashboard. So at the top of the window, you can see this srv-crgXXX or something like that, So that’s the service id.

So that’s pretty much all for this article. I hope it helped you. So I’ll see you in the next one. Till then bye bye.