# Building a Simple MERN Stack App—A Hands-On Walkthrough 💻

Welcome to Day 1 of my daily blogging series! Today, we’ll dive into creating a minimal MERN stack app from scratch. By the end of this post, you’ll have:

* A basic Express and Node.js backend with a single API endpoint.
    
* A MongoDB database connected via Mongoose.
    
* A React front end that fetches data from your backend.
    
* A deployed version of your app (optional).
    

> **Note:** If you’re new to any piece of this stack, feel free to bookmark this tutorial and revisit as you get more familiar. Let’s get started!

---

## Project Setup & Folder Structure

First, create a new folder for your project. In your terminal:

```bash
mkdir mern-todo-app
cd mern-todo-app
```

Inside, we’ll have two main directories: `server` and `client`:

```pgsql
mern-todo-app/
├── server/
└── client/
```

* `server/`: All backend-related code (Express, Node.js, MongoDB).
    
* `client/`: React front end (using Create React App).
    

---

## Backend: Express & MongoDB

### Initialize the Server

Navigate to `server/` and initialize a Node project:

```bash
cd server
npm init -y
```

Install dependencies:

```bash
npm install express mongoose cors dotenv
```

* `express`: Web framework.
    
* `mongoose`: MongoDB ODM.
    
* `cors`: Allow cross-origin requests.
    
* `dotenv`: Manage environment variables.
    

In `server/`, create a file named `server.js`:

```javascript
// server/server.js
import express from 'express';
import mongoose from 'mongoose';
import cors from 'cors';
import dotenv from '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.error('❌ MongoDB connection error:', err));

// Simple Mongoose Schema
const todoSchema = new mongoose.Schema({
  text: { type: String, required: true },
  completed: { type: Boolean, default: false },
});

const Todo = mongoose.model('Todo', todoSchema);

// Routes
app.get('/api/todos', async (req, res) => {
  try {
    const todos = await Todo.find();
    res.json(todos);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
});

app.post('/api/todos', async (req, res) => {
  const { text } = req.body;
  const newTodo = new Todo({ text });
  try {
    const savedTodo = await newTodo.save();
    res.status(201).json(savedTodo);
  } catch (err) {
    res.status(400).json({ message: err.message });
  }
});

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

Add a `.env` file in `server/`:

```ini
MONGO_URI=your_mongodb_connection_string_here
```

### Run the Server

In `server/` directory, add a start script to `package.json`:

```json
"scripts": {
  "start": "node --experimental-modules server.js"
}
```

Then run:

```bash
npm start
```

You should see “MongoDB connected” and “Server running on port 5000” in your console.

---

## Front End: React Application

### Bootstrap React

In the project root (`mern-todo-app/`), run:

```bash
npx create-react-app client
```

Navigate into `client/`:

```bash
cd client
```

Install Axios (or fetch is fine, but Axios simplifies JSON calls):

```bash
npm install axios
```

### Building the Todo Interface

In `client/src/App.js`, replace with:

```javascript
// client/src/App.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [todos, setTodos] = useState([]);
  const [text, setText] = useState('');

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

  const fetchTodos = async () => {
    try {
      const res = await axios.get('http://localhost:5000/api/todos');
      setTodos(res.data);
    } catch (err) {
      console.error(err);
    }
  };

  const addTodo = async (e) => {
    e.preventDefault();
    if (!text) return;
    try {
      await axios.post('http://localhost:5000/api/todos', { text });
      setText('');
      fetchTodos();
    } catch (err) {
      console.error(err);
    }
  };

  return (
    <div style={styles.container}>
      <h1 style={styles.heading}>My TODO App (MERN Stack)</h1>
      <form onSubmit={addTodo} style={styles.form}>
        <input
          type="text"
          value={text}
          onChange={(e) => setText(e.target.value)}
          placeholder="Enter a task..."
          style={styles.input}
        />
        <button type="submit" style={styles.button}>
          Add Todo
        </button>
      </form>
      <ul style={styles.list}>
        {todos.map((todo) => (
          <li key={todo._id} style={styles.listItem}>
            {todo.text}
          </li>
        ))}
      </ul>
    </div>
  );
}

const styles = {
  container: {
    maxWidth: '600px',
    margin: '2rem auto',
    padding: '1rem',
    textAlign: 'center',
    fontFamily: 'Arial, sans-serif',
  },
  heading: {
    marginBottom: '1.5rem',
  },
  form: {
    display: 'flex',
    justifyContent: 'center',
    marginBottom: '1rem',
  },
  input: {
    padding: '0.5rem',
    width: '60%',
    fontSize: '1rem',
  },
  button: {
    padding: '0.5rem 1rem',
    marginLeft: '0.5rem',
    fontSize: '1rem',
  },
  list: {
    listStyle: 'none',
    padding: 0,
  },
  listItem: {
    background: '#f8f8f8',
    margin: '0.5rem 0',
    padding: '0.75rem',
    borderRadius: '4px',
    textAlign: 'left',
  },
};

export default App;
```

Start the React app:

```bash
npm start
```

It should open on [`http://localhost:3000`](http://localhost:3000), showing a header, input field, and empty list.

---

## Testing It Out

* Make sure your backend server ([`localhost:5000`](http://localhost:5000)) is running.
    
* In the front end, type a new to-do (e.g., “Learn MERN Stack”) and click **Add Todo**.
    
* Check the list below—your new task should appear, pulled from MongoDB.
    

---

## (Optional) Deploying to Production

If you want to deploy, here’s a quick outline:

### Backend (Heroku, Render, or similar):

* Update `server.js` to serve the front end in production:
    
    ```javascript
    // After your API routes in server.js
    if (process.env.NODE_ENV === 'production') {
      app.use(express.static('../client/build'));
      app.get('*', (req, res) =>
        res.sendFile(path.resolve(__dirname, '../client', 'build', 'index.html'))
      );
    }
    ```
    
* Push to Heroku, ensure `MONGO_URI` is set in Heroku’s config vars.
    

### Frontend (Vercel, Netlify, or serve from Heroku):

* In `client/`, run `npm run build` to generate a production bundle.
    
* If using separate hosts, deploy the `build/` folder (Netlify/Vercel).
    
* Update the Axios base URL to your live backend URL.
    

---

## Wrapping Up

Congratulations! 🎉 You’ve built a functional MERN stack todo app:

* **Express/Node.js** server with API endpoints
    
* **MongoDB** for data storage via **Mongoose**
    
* **React** front end fetching and displaying data
    

This basic project lays the foundation for scaling up—adding authentication, advanced routing, Redux/Context for state, or responsive styling with Tailwind. In Day 2, we’ll explore state management in React and dive deeper into Hooks. Stay tuned!

> In this tutorial, you'll learn to create a minimal MERN stack app from scratch. By the end, you'll have a basic Express and Node.js backend with MongoDB connected via Mongoose, a React front end fetching data from your backend, and an optional deployed version of your app. The guide includes full setup instructions, from project initialization to running both the server and React app locally. Stay tuned for Day 2, where we'll explore state management in React with Hooks.
