Personal growth: Build an Interactive Portfolio with Next.js and BCMS
Published: 2024-02-14 15:41:30

Creating a personal website that strikes the perfect balance between visual appeal and SEO-friendliness is well within the reach of developers, and BCMS, a headless [CMS for NextJS](https://thebcms.com/blog/choosing-cms-for-nextjs), is here to make that journey even smoother.

In this tutorial, you'll explore how, as a developer, you can craft a personal website that not only looks great but also ranks well in search engines. You'll also learn why BCMS is the ideal choice for achieving this.

BCMS is more than just a content management system; it's a dynamic tool designed with developers in mind. Here's why BCMS is the perfect choice for your personal website project:

User-Friendly Interface: BCMS offers a simple and intuitive interface, making it easy for developers to manage and model content effortlessly. You don't need to be a CMS expert to navigate it easily.

Modern Technology Stack: BCMS is built on a modern tech stack, aligning perfectly with the development trends and tools you already know. It ensures you can leverage your existing skills to create a fantastic website.

Efficiency and Speed: One of BCMS's standout features is its efficiency. It empowers you to streamline your development process, saving time and effort in content management and allowing you to focus on what truly matters – your website's content and design.

## The BCMS Personal Starter


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

Introducing the BCMS Personal Starter, a carefully crafted website template built with Next.js, the popular React framework for frontend development. The BCMS Personal Starter is built to help you get your site up and running without worrying about design.

This template is a starting point, allowing you to hit the ground running with your website development. It comes pre-configured with the necessary components and styles, giving you a head start and letting you customize and tailor it to your unique vision and requirements.

Check out the [repo](https://github.com/bcms/starters/tree/master/next/personal) to get started.

## Let's Get Started

Now that you understand the power and potential of BCMS, it's time to dive into the practical aspects of building your personal website. This tutorial will guide you through each step, providing clear instructions and real-life examples to ensure you can put your developer skills to good use and create a personal website with ease.

There are three parts to this tutorial:

- Setting up the BCMS.
- Setting up Next.js Frontend.
- Deploying the code to Vercel.

## Setting up the BCMS

Most traditional CMSs are very complicated to set up, even for developers. One of the problems BCMS solves is removing all the unnecessary steps you need to set up a CMS. You can set up and run your BCMS in a matter of minutes.

BCMS comes in two options - Locally hosted, which you manage and host yourself, and the recommended option, the cloud version, which is hosted and managed by BCMS.

For this article, we will be using the locally hosted option. Check out this [tutorial](https://docs.thebcms.com/install/locally) on how to set up BCMS locally, or head to the [BCMS website](https://thebcms.com/) to sign up for the cloud version. Now that you've set up the environment let's move to the next step.

### Setting up the Local Environment

To begin, install the BCMS CLI:

```
npm install @becomes/cms-cli -g
```
Verify the installation by running:

```
bcms --help
```
Create a new instance of BCMS with the CLI and follow the prompts. For the project name, I will put 'bcms' just to stay consistent.

```
bcms --cms create
```
Setup is set; let's run the server. This step will pull some docker images. Wait for it to finish.

```
docker-compose up
```

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

Go to `http://localhost:8080` to verify our server is running.


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

Voila! We have successfully set up a local instance of BCMS.

### Creating Data Models for frontend

Alright, now let's talk about data models. In the BCMS world, it's all about how you structure your data. It's like the blueprint for your content, where you specify the fields and their data types.

Let's put it in context. If you're dealing with products or articles, your data model might look something like this:

```
//Product

product_name: string
product_price: number
product_sku: number
product_image: string[]
product_quanity: number
```
BCMS simplifies this process. Data modeling and content creation in BCMS are a breeze, with just two steps:

- Templates: These are pre-defined structures for your content. Based on these templates, you can create one or more content.
- Entries: These are individual records or content based on a template. Think of a template as the blueprint for what an entry should look like.

Now that you've got a better grip on BCMS data modeling, let's move on with our tutorial.

Before we create templates, it's a good idea to have a clear vision of what they should look like. In our case, we're building a personal site that looks like this:


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

Looking at this design, we'll need a title, about me text, contact links, skills with years of experience, and a photo. Let's head to BCMS and bring it to life.

Open your browser and go to "http://localhost:8080", then click "Templates."


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

Create a new template called "homepage." You can add an optional description, but we'll leave it blank. Choose "single entry" because the homepage content is unique and serves a single purpose.


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

Based on the design I am aiming for, let's add template properties:

```
title: string
about_me: RichText
image: Media

```

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

Now, let's create templates for skills and contact links using the same process. The only difference is that this time, I won't choose "single entry."


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

Skills template

```
name: string
years_of_experience: number

```
Contact links template

```
label: string
href: string

```
Now that all templates are ready, let's proceed to entries and adding data. Add all the required data for the homepage, contact list, and skills, just like this:


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


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


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

Phew! You're doing great. This is how to set up BCMS successfully. It's easy, straightforward, and, most importantly, developer-friendly. Keep up the good work, and stay tuned for the next part of this exciting journey.

## Setting up the Nextjs frontend

Next.js, a robust React framework, streamlines the development of fast and scalable web applications while enhancing developer experience and performance. 

In this tutorial, I'll use the BCMS CLI to scaffold a customized Next.js project that seamlessly integrates with BCMS effortlessly. By simply executing the BCMS CLI command and specifying your project's name and type, you'll have a fully prepared Next.js project ready to go.

Learn more: [Why BCMS is the Best CMS for NextJS: 6 Less Obvious Reasons](https://thebcms.com/blog/the-best-cms-for-nextjs)

<aside> 💡 Projects scaffolded using BCMS CLI come with native support for typescript. Type safe, stay safe. </aside>

Navigate to the "personal-site" directory created earlier and execute the BCMS CLI command:

```
cd personal site && bcms --website create

```
You'll be prompted to select a framework, and in our case, it's Next.js. Wait for the process to complete, then open your project in your IDE to begin integrating BCMS.

### Creating API keys For The Frontend

To use BCMS in our Next.js project, you need API keys. Visit the BCMS server, go to "Key Management," and click "Add New Key." For this tutorial, let's name it "PERSONAL_SITE."


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


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

Now that we have the key let's proceed to add it to our Next.js project.

Within the project, navigate to the `bcms.config.js` file and add our newly created keys. The "origin" field should point to our server's URL, which, in this case, is `[http://localhost:8080]` (Be sure to update this to your production URL when you deploy the server).

<aside> 💡 It's recommended to store your API keys in an environment file. </aside>

```
const { createBcmsMostConfig } = require('@becomes/cms-most');

module.exports = createBcmsMostConfig({
  cms: {
    origin:
      process.env.BCMS_API_ORIGIN ||
      'http://localhost:8080',
    key: {
      id: process.env.BCMS_API_KEY || '654246b0be81ac0b54dbd06f',
      secret:
        process.env.BCMS_API_SECRET ||
        'a4a3b327bd9cc015c905c7c3340efb55976d97c1e2e1446cc3bbc62bb860143f',
    },
  },
  media: {
    output: 'public/api',
    download: true,
  },
  enableClientCache: true,
});

```
Likewise, go to the "_app.tsx" file and add our API keys:

```
import '../styles/globals.css';
import type { AppProps } from 'next/app';
import { BCMSImageConfig } from '@becomes/cms-most/frontend';

BCMSImageConfig.cmsOrigin =
  process.env.NEXT_PUBLIC_BCMS_API_ORIGIN ||
  'http://localhost:8080';
BCMSImageConfig.publicApiKeyId =
  process.env.NEXT_PUBLIC_BCMS_API_PUBLIC_KEY_ID || '654246b0be81ac0b54dbd06f';

function MyApp({ Component, pageProps }: AppProps): JSX.Element {
  return <Component {...pageProps} />;
}

export default MyApp;

```
With API keys added to the project, it is time to verify if it can fetch data by running npm run dev to start the development server.

### Fetching And Displaying Data On The Frontend

I will use Next.js' `getStaticProps` to fetch our data and the official BCMS client library to interact with the CMS, which is already included in our project.

Let's create the `getStaticProps` function in our "index.tsx" file:

```
export const getStaticProps: GetStaticProps = async () => {
  
};

```
Now, let’s add the `BCMS client library` and fetch the `homepage_entry`

```
export const getStaticProps: GetStaticProps = async () => {
    const client = getBcmsClient();
    const data = await client.entry.get({template: 'home_page', entry: 'home'}) as HomePageEntry;
    const parsedData = data.meta.en;
    return {
        props: {
            ...parsedData
        }
    };
};

```
In this step, I instantiate the `getBcmsClient`, fetch a single entry (homepage entry) by providing the template ID and the entry title (found on the BCMS server), and return the data.

In the same function, let's fetch skills and contact links entries:

```
export const getStaticProps: GetStaticProps = async () => {
    const client = getBcmsClient();
    
    const homepage = await client.entry.get({template: 'home_page', entry: 'home'}) as HomePageEntry;
    
    const skills = await client.entry.getAll({template: 'skills'}) as SkillsEntry[]
    
    const contactList = await client.entry.getAll({template: 'contact_list'}) as ContactListEntry[]
   
    return {
        props: {
            homepage: homepage.meta.en,
            skills: skills.map(s => s.meta.en),
            contactList: contactList.map(s => s.meta.en)
        }
    };
};

```
In this step, I fetched the skills and contact list entries using the BCMS client getAll and returning the data.

<aside> 💡 BCMS generates type definitions for entries and templates, which can be imported from .`/bcms/types`</aside>

Now, let's display the data on the index page component. I'll use components created by BCMS to handle complex data types like "rich text" and "images." These components simplify parsing and displaying these data types. I'll use **BCMSContentManager** for rich text and **BCMSImage** for images.

```
const Home: NextPage<HomePageProps> = (props) => {
  return (
    <div>
      <div>
        <div>
          <div>
            <h1>Jay Auwal</h1>
            <div />
          </div>
          <div>
            <div>
              <h3>About me</h3>
              <BCMSContentManager
                items={props.homepage.about_me}
                widgetComponents={{}}
              />
              <div>
                {props.contactList.map((contact, index) => (
                  <Link href={contact.href as string} key={index}>
                    {contact.label}
                  </Link>
                ))}
              </div>
            </div>
            <div>
              <BCMSImage media={props.homepage.image} />
            </div>
            <div>
              <h3>Skills</h3>
              <div>
                {props.skills.map((s, index) => (
                  <div key={index}>
                    <h3>{s.name}</h3>
                    <span>{`${s.years_of experience} years of experience`}</span>
                  </div>
                ))}
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

```
In this step, I got my data from BCMS via `getStaticProps` and display that data on the frontend using `TSX/JSX`.

Now, let’s add styling to the code to make it prettier. I will be using Tailwind to do that. we won’t go deep into a tailwind. I will add the classes, and our code will look like this:

```
const Home: NextPage<HomePageProps> = ( props) => {
  return (
    <div className="bg-white flex-1 h-full">
      <div className="mx-auto px-[100px] py-10">
        <div className="flex flex-col">
          <div className="flex flex-row items-baseline w-full">
              <h1 className="text-[160px] leading-[80px] text-gray-600">Jay Auwal</h1>
              <div className="rounded-full w-12 h-12 bg-gray-600 my-5" />
          </div>
            <div className="grid grid-cols-3 mt-10 gap-5 w-full">
                <div className="flex flex-col">
                    <h3 className="font-bold text-4xl mb-4">About me</h3>
                    <BCMSContentManager
                        className="text-gray-600 font-medium leading-8"
                        items={props.homepage.about_me}
                        widgetComponents={{}}
                        />
                    <div className="flex mt-auto pb-5 flex-wrap space-x-3 items-center underline">
                        {props.contactList.map((contact, index) => (
                            <Link href={contact.href as string} key={index}>
                                {contact.label}
                            </Link>
                        ))}
                    </div>
                </div>
                <div className="overflow-hidden">
                    <BCMSImage
                       className="aspect-[4/3]"
                       media={props.homepage.image}
                    />
                </div>
                <div className="flex flex-col">
                    <h3 className="font-bold text-xl mb-4">Skills</h3>
                    <div className="grid grid-row-1 gap-5">
                        {props.skills.map((s, index) => (
                            <div key={index} className="rounded-lg border-[1px] border-gray-600 p-5">
                                <h3 className="font-bold text-xl">{s.name}</h3>
                                <span className="text-gray-600">{`${s.years_of_experience} years of experience`}</span>
                            </div>
                        ))}
                    </div>
                </div>
            </div>
        </div>
      </div>
    </div>
  );
};

```
Perfect! BCMS and Next.js integration is done.

## Deploying the code to Vercel

The simplest way to deploy a nextjs application is using Vercel.

First, make sure your project is working and getting built correctly. Run `npm run build`, and if there are no errors, then we are good to go.

Create a Vercel account

Connect your GitHub account with Vercel

Push your code to the main branch

Import the project from GitHub to your Vercel account

Create environmental variables (API keys and ID)

And click on deploy

You can learn more about deploying to Vercel in this [article](https://nextjs.org/learn-pages-router/basics/deploying-nextjs-app/deploy).

## BCMS Portfolio starter: Get ready to show the world who you are

This is what [BCMS and NextJS](https://thebcms.com/nextjs-cms) look like. You've learned how to create and manage API keys, fetch data from BCMS, and display it on the frontend. You can build countless [NextJS examples](https://thebcms.com/blog/nextjs-websites-examples) that are powerful, content-driven web applications using this foundation. 

Remember that BCMS generates type definitions for entries and templates, making your development process more efficient and type-safe. You can explore and customize your project further, adding your unique features and design elements.

I hope this tutorial has been helpful in your journey to create your personal site or any content-driven web application. Thank you for joining us, and best of luck with your projects. If you have any questions or need further assistance, feel free to reach out. Happy coding!