As a software developer and tutor, creating a full-stack portfolio is an excellent way to showcase your skills, projects, and expertise. In this article, I’ll walk you through how to build a modern, responsive portfolio using the MERN stack (MongoDB, Express.js, React.js, and Node.js). By the end of this guide, you’ll have a fully functional portfolio that you can deploy and share with the world.
Why the MERN Stack?
The MERN stack is a popular choice for full-stack development because:
- JavaScript Everywhere: You use JavaScript for both frontend and backend development, making it easier to maintain.
 - Scalability: MongoDB and Node.js are highly scalable, making them suitable for projects of any size.
 - Community Support: With a large and active community, you’ll find plenty of resources and tutorials to help you along the way.
 
Portfolio Features
Our portfolio will include the following features:
- Homepage: A brief introduction and overview of your skills.
 - Projects Section: A showcase of your work with descriptions and links.
 - Blog/Tutorials Section: A space to share your knowledge as a tutor.
 - Contact Form: A way for visitors to reach out to you.
 
Step 1: Setting Up the Project
1.1 Create the Project Structure
Start by creating a project folder and setting up the backend and frontend:
mkdir dhanian-portfolio
cd dhanian-portfolio
# Backend setup
mkdir backend
cd backend
npm init -y
npm install express mongoose cors dotenv
# Frontend setup
cd ..
npx create-react-app frontend
cd frontend
npm install axios react-router-dom
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
1.2 Backend Setup
The backend will handle the contact form submissions and serve as the API for your portfolio.
1.2.1 Create the Backend Structure
backend/
├── models/
├── routes/
├── controllers/
├── .env
├── server.js
1.2.2 Set Up the Server
In backend/server.js, add the following code:
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const dotenv = require('dotenv');
dotenv.config();
const app = express();
const PORT = process.env.PORT || 5000;
// Middleware
app.use(cors());
app.use(express.json());
// MongoDB Connection
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true })
  .then(() => console.log('MongoDB Connected'))
  .catch(err => console.log(err));
// Routes
app.get('/', (req, res) => {
  res.send('Backend is running');
});
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
1.2.3 Add a Contact Model
Create a Contact model in backend/models/Contact.js:
const mongoose = require('mongoose');
const ContactSchema = new mongoose.Schema({
  name: { type: String, required: true },
  email: { type: String, required: true },
  message: { type: String, required: true },
});
module.exports = mongoose.model('Contact', ContactSchema);
1.2.4 Add a Contact Route
Create a route for the contact form in backend/routes/contact.js:
const express = require('express');
const router = express.Router();
const Contact = require('../models/Contact');
router.post('/', async (req, res) => {
  const { name, email, message } = req.body;
  try {
    const newContact = new Contact({ name, email, message });
    await newContact.save();
    res.status(201).json({ message: 'Message sent successfully' });
  } catch (err) {
    res.status(500).json({ error: 'Server error' });
  }
});
module.exports = router;
1.2.5 Update the Server to Use the Contact Route
In backend/server.js, add:
const contactRoutes = require('./routes/contact');
app.use('/api/contact', contactRoutes);
1.3 Frontend Setup
The frontend will be built using React.js and styled with Tailwind CSS.
1.3.1 Configure Tailwind CSS
Update frontend/tailwind.config.js:
module.exports = {
  content: ['./src/**/*.{js,jsx,ts,tsx}'],
  theme: {
    extend: {},
  },
  plugins: [],
};
Add Tailwind to frontend/src/index.css:
@tailwind base;
@tailwind components;
@tailwind utilities;
1.3.2 Create the Homepage
In frontend/src/components/Home.js, add:
import React from 'react';
const Home = () => {
  return (
    <div className="min-h-screen bg-gray-100 flex items-center justify-center">
      <h1 className="text-4xl font-bold text-blue-600">Welcome to Dhanian's Portfolio</h1>
    </div>
  );
};
export default Home;
1.3.3 Set Up Routing
In frontend/src/App.js, add:
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import Home from './components/Home';
function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
      </Routes>
    </Router>
  );
}
export default App;
Step 2: Connect Frontend and Backend
2.1 Create a Contact Form
In frontend/src/components/Contact.js, add:
import React, { useState } from 'react';
import axios from 'axios';
const Contact = () => {
  const [formData, setFormData] = useState({ name: '', email: '', message: '' });
  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      await axios.post('http://localhost:5000/api/contact', formData);
      alert('Message sent successfully');
    } catch (err) {
      alert('Error sending message');
    }
  };
  return (
    <form onSubmit={handleSubmit} className="max-w-md mx-auto mt-10">
      <input
        type="text"
        placeholder="Name"
        value={formData.name}
        onChange={(e) => setFormData({ ...formData, name: e.target.value })}
        className="w-full p-2 mb-4 border rounded"
      />
      <input
        type="email"
        placeholder="Email"
        value={formData.email}
        onChange={(e) => setFormData({ ...formData, email: e.target.value })}
        className="w-full p-2 mb-4 border rounded"
      />
      <textarea
        placeholder="Message"
        value={formData.message}
        onChange={(e) => setFormData({ ...formData, message: e.target.value })}
        className="w-full p-2 mb-4 border rounded"
      />
      <button type="submit" className="w-full p-2 bg-blue-600 text-white rounded">
        Send
      </button>
    </form>
  );
};
export default Contact;
2.2 Add the Contact Route to App.js
Update frontend/src/App.js:
import Contact from './components/Contact';
function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/contact" element={<Contact />} />
      </Routes>
    </Router>
  );
}
Step 3: Deploy the Portfolio
- Backend: Deploy to Render or Heroku.
 - Frontend: Deploy to Vercel or Netlify.
 
Conclusion
By following this guide, you’ve built a full-stack portfolio using the MERN stack. This portfolio not only showcases your skills but also demonstrates your ability to build modern, scalable web applications. Feel free to expand it by adding more features, such as authentication, a blog section, or even a dark mode toggle.
    
Top comments (0)