Stock Market Portfolio App using MERN Stack

Last Updated : 30 Mar, 2026

The Stock Market Portfolio project is a web application that helps users manage and track their investments efficiently. Built using the MERN stack, it offers a scalable and responsive solution for modern financial management.

Prerequisites

Ensure you have the required technologies and tools installed to build and run the MERN-based application.

Create Stock Market Portfolio App

Follow this approach to build a dynamic stock portfolio management application.

  • The database stores a list of stock data fetched by the server.
  • Users can also manually add stock data via API requests.
  • The frontend includes two routes: one for all stocks and another for watchlisted stocks.
  • Users can add favorite stocks to a watchlist.
  • Stock prices are displayed in green if increasing and red if decreasing.

Steps to Create the Project

Follow these steps to build a full-stack stock market portfolio application using the MERN stack.

Step 1: Create a folder for the project backend and initialized the Express Application.

mkdir stock-market-portfolio
cd stock-market-portfolio
npm init -y

Step 2: Install Express and other required packages:

npm install express mongoose body-parser cors

Folder Structure:

hk

Dependencies (Backend):

"dependencies": {
    "body-parser": "^1.20.2",
    "cors": "^2.8.5",
    "express": "^4.18.2",
    "mongoose": "^8.0.4"
}

Example: Create a file named server.js and add the following code.

server.js
const express = require("express");
const mongoose = require("mongoose");
const cors = require("cors");
const bodyParser = require("body-parser");

const app = express();
const PORT = process.env.PORT || 5000;

app.use(cors());
app.use(bodyParser.json());

const uri = "Your Mongo URI";

mongoose
  .connect(uri)
  .then(() => console.log("MongoDB connected"))
  .catch((err) => {
    console.error("MongoDB connection error:", err);
    process.exit(1);
  });

const stockSchema = new mongoose.Schema({
  company: String,
  description: String,
  initial_price: Number,
  price_2002: Number,
  price_2007: Number,
  symbol: String,
});

const Stock = mongoose.model("Stock", stockSchema, "stocks");

const watchlistSchema = new mongoose.Schema({
  stockId: { type: mongoose.Schema.Types.ObjectId, ref: "Stock" },
  addedAt: { type: Date, default: Date.now },
});

const Watchlist = mongoose.model("Watchlist", watchlistSchema);

app.get("/api/stocks", async (req, res) => {
  try {
    const stocks = await Stock.find();
    res.json(stocks);
  } catch (error) {
    res.status(500).json({ error: "Internal Server Error" });
  }
});

app.get("/api/watchlist", async (req, res) => {
  try {
    const list = await Watchlist.find().populate("stockId");
    res.json(list);
  } catch (error) {
    res.status(500).json({ error: "Internal Server Error" });
  }
});

app.post("/api/watchlist", async (req, res) => {
  try {
    const { stockId } = req.body;
    const exists = await Watchlist.findOne({ stockId });
    if (exists) return res.json({ message: "Already in watchlist" });
    const item = new Watchlist({ stockId });
    await item.save();
    res.json({ message: "Added to watchlist" });
  } catch (error) {
    res.status(500).json({ error: "Internal Server Error" });
  }
});

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`);
});

Step 3: Open the MongoDB atlas or compass and insert the following JSON file in the "stocks" collection.

"https://gist.github.com/stevekinney/f96d5800852e91282f46#file-stocks-json".

Step 4: Create the Frontend (React.js) by running the below command.

npx create-react-app stock-market-frontend
cd stock-market-frontend

Step 5: Install the required dependencies.

npm install axios

Dependencies (Frontend):

"dependencies": {
    "@emotion/react": "^11.11.3",
    "@emotion/styled": "^11.11.0",
    "@mui/material": "^5.15.4",
    "@testing-library/jest-dom": "^5.17.0",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "axios": "^1.6.5",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-router-dom": "^6.21.2",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
}

Example: Write the given code in the respective files.

App.css
/* src/App.css */
body {
    font-family: 'Arial', sans-serif;
    background-color: #d9d7ca;
    margin: 0;
    padding: 0;
}
.App {
    text-align: center;
    padding: 20px;
}
h1 {
    color: #1f454d;
}
h2 {
    color: #3c8d93;
    margin-top: 30px;
}
ul {
    list-style-type: none;
    padding: 0;
}
li {
    background-color: #3c8d93;
    color: #d9d7ca;
    padding: 10px;
    margin: 10px 0;
    border-radius: 5px;
    display: flex;
    justify-content: space-between;
    align-items: center;
}
button {
    background-color: #1f454d;
    color: #d9d7ca;
    border: none;
    padding: 8px;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s ease;
}
button:hover {
    background-color: #3c8d93;
}
/* Navigation bar styles */
nav {
    background-color: #1f454d;
    padding: 15px 0;
}
nav a {
    color: #d9d7ca;
    text-decoration: none;
    margin: 0 20px;
    font-size: 18px;
    transition: color 0.3s ease;
}
nav a:hover {
    color: #3c8d93;
}
App.js
// src/App.js
import React, { useState, useEffect } from "react";
import {
  BrowserRouter as Router,
  Routes,
  Route,
  NavLink,
  Navigate,
} from "react-router-dom";
import "./App.css";

function computeColor(stock) {
  if (!stock) return "black";
  const current = stock.initial_price;
  const compare = stock.price_2007;
  if (typeof current === "number" && typeof compare === "number") {
    return current >= compare ? "green" : "red";
  }
  return "black";
}

const Stocks = ({ addToWatchlist }) => {
  const [stocks, setStocks] = useState([]);

  useEffect(() => {
    fetch("http://localhost:5000/api/stocks")
      .then((res) => res.json())
      .then((data) => setStocks(data))
      .catch((error) => console.error("Error fetching stocks:", error));
  }, []);

  return (
    <div className="App" style={{ padding: 16 }}>
      <h1>Stock Market MERN App</h1>
      <h2>Stocks</h2>
      <ul>
        {stocks.map((stock) => (
          <li key={stock._id || stock.symbol} style={{ marginBottom: 8 }}>
            <strong>{stock.company}</strong> ({stock.symbol}) -
            <span style={{ color: computeColor(stock), marginLeft: 8 }}>
              ${stock.initial_price ?? "N/A"}
            </span>
            <button
              style={{ marginLeft: 12 }}
              onClick={() => addToWatchlist(stock)}
            >
              Add to My Watchlist
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
};

const Watchlist = ({ watchlist }) => {
  return (
    <div className="App" style={{ padding: 16 }}>
      <h1>Stock Market MERN App</h1>
      <h2>My Watchlist</h2>
      {watchlist.length === 0 ? (
        <p>No items in watchlist.</p>
      ) : (
        <ul>
          {watchlist.map((item) => {
            const stock = item.stockId || item;
            return (
              <li key={item._id} style={{ marginBottom: 8 }}>
                <strong>{stock.company}</strong> ({stock.symbol}) -
                <span style={{ marginLeft: 8 }}>
                  ${stock.initial_price ?? "N/A"}
                </span>
              </li>
            );
          })}
        </ul>
      )}
    </div>
  );
};

function App() {
  const [watchlist, setWatchlist] = useState([]);

  const loadWatchlist = () => {
    fetch("http://localhost:5000/api/watchlist")
      .then((res) => res.json())
      .then((data) => setWatchlist(data))
      .catch((err) => console.error("Error loading watchlist:", err));
  };

  useEffect(() => {
    loadWatchlist();
  }, []);

  const addToWatchlist = (stock) => {
    fetch("http://localhost:5000/api/watchlist", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ stockId: stock._id }),
    })
      .then((res) => res.json())
      .then((data) => {
        alert(data.message || "Action completed");
        loadWatchlist();
      })
      .catch((error) => {
        console.error("Error adding to watchlist:", error);
        alert("Failed to add to watchlist");
      });
  };

  return (
    <Router>
      <nav style={{ padding: 12 }}>
        <NavLink to="/stocks" style={{ marginRight: 12 }}>
          Stocks
        </NavLink>
        <NavLink to="/watchlist">Watchlist</NavLink>
      </nav>

      <Routes>
        <Route path="/" element={<Navigate to="/stocks" replace />} />
        <Route path="/stocks" element={<Stocks addToWatchlist={addToWatchlist} />} />
        <Route path="/watchlist" element={<Watchlist watchlist={watchlist} />} />
      </Routes>
    </Router>
  );
}

export default App;


Step 6: Start backend server

cd stock-market-portfolio
npm start

Step 7: Start frontend

cd stock-market-frontend
npm start

Output:

Comment

Explore