Skip to Content
Lesson 2

Hosting & Production Preparation

Workplace Context

Your team has decided on a CI/CD strategy and is now ready to deploy your MERN application. As a developer on the team, you are tasked with preparing the codebase for a live production environment and selecting a suitable hosting provider. This isn’t just about running npm start on a different machine; it involves making critical decisions about infrastructure, security, and performance. You’ll need to compare hosting models, configure your application to run efficiently and securely, and ensure that both the frontend and backend can communicate with each other once they are live on the internet.


Lesson Objectives

  • Compare and contrast Infrastructure as a Service (IaaS) and Platform as a Service (PaaS) hosting models.
  • Identify the steps required to prepare a MERN application for a production environment.
  • Explain how to manage environment variables securely for production.
  • Configure an Express server to serve a production React build.
  • Describe how to handle Cross-Origin Resource Sharing (CORS) in a production deployment.

Choosing a Hosting Provider

Before your application can be live, its code needs to run on a server that is connected to the internet. “Hosting” is the service of providing and maintaining these servers. There are several models for hosting, but two are most common for web applications.

Infrastructure as a Service (IaaS)

IaaS provides the fundamental building blocks of computing infrastructure — virtual servers, storage, and networking — on a pay-as-you-go basis. You rent the hardware, but you are responsible for managing everything from the operating system upwards.

  • Examples: Amazon Web Services (AWS) EC2, Google Compute Engine, DigitalOcean Droplets.
  • Analogy: It’s like leasing an empty plot of land. You have complete freedom to build whatever you want, but you’re also responsible for the foundation, plumbing, and construction.
  • Pros: Maximum control and flexibility. You can configure every detail of your environment.
  • Cons: Requires significant system administration knowledge (DevOps), more complex to set up and maintain, and you are responsible for security patches, scaling, and backups.

Platform as a Service (PaaS)

PaaS provides a platform where customers can develop, run, and manage applications without the complexity of building and maintaining the underlying infrastructure. The provider handles the servers, operating systems, and scaling. You just provide your application code.

  • Examples: Render, Heroku, Vercel (for frontends), Netlify (for frontends).
  • Analogy: It’s like renting a fully furnished apartment. You don’t worry about the building’s maintenance; you just move in and arrange your belongings (your code).
  • Pros: Easy to use, rapid deployment, automated scaling, and simplified management. Lets developers focus on writing code, not managing servers.
  • Cons: Less control over the underlying environment, can be more expensive at a very large scale, and may have platform-specific limitations.

For most MERN stack applications, a PaaS like Render.com is an ideal starting point because it streamlines the deployment process for both Node.js backends and React frontends.


Preparing Your App for Production

Moving from a development environment to a production one requires several crucial configuration changes to ensure the application is performant, secure, and stable.

1. Production Builds

Your code needs to be optimized for production.

  • Frontend (React): You never deploy your development server (webpack-dev-server). Instead, you run the command npm run build. This process, managed by tools like Vite, does the following:

    • Bundles all your JavaScript files into a few, smaller files.
    • Minifies the code by removing whitespace and shortening variable names.
    • Transpiles modern JavaScript and JSX into code that is compatible with a wider range of browsers.
    • The result is a highly optimized build folder containing static HTML, CSS, and JavaScript files.
  • Backend (Express): While Node.js code isn’t “built” in the same way as a React app, it’s critical to ensure all development-only dependencies (devDependencies) are pruned by running npm install --production.

2. Environment Variables

This is the most critical step for security and configuration. Your .env file must never be committed to Git. It is for local development only. Production secrets (like database connection strings and API keys) are managed directly within the hosting provider’s dashboard.

Common production environment variables include:

  • NODE_ENV=production: Many libraries (including Express) change their behavior and optimize for performance when this is set.
  • DATABASE_URL: The connection string for your live MongoDB Atlas database.
  • JWT_SECRET: The secret key used to sign JSON Web Tokens.
  • PORT: The port your web server will listen on. PaaS providers typically set this automatically.
  • CLIENT_ORIGIN: The URL of your live frontend (e.g., https://my-cool-app.onrender.com), used for CORS.

3. Securing CORS for Production

In development, you might have used a very open CORS policy, like app.use(cors()), which allows requests from any origin. This is insecure and must be changed for production.

You should configure your Express server to only allow requests from your deployed frontend’s domain.

// In your server.js or app.js const cors = require('cors'); const corsOptions = { origin: process.env.CLIENT_ORIGIN, // e.g., 'https://my-awesome-app.onrender.com' optionsSuccessStatus: 200 // For legacy browser support }; app.use(cors(corsOptions));

4. Serving the Frontend from the Backend

For a simple MERN deployment, a common pattern is to have your Express server serve the static files generated by the React npm run build command.

This involves two steps in your server.js:

// 1. Tell Express where to find static assets (the 'build' folder) app.use(express.static(path.join(__dirname, 'client/build'))); // Your API routes go here... app.use('/api/users', userRoutes); app.use('/api/tasks', taskRoutes); // 2. A "catch-all" route to send index.html for any other request. // This allows React Router to handle client-side navigation. app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'client/build', 'index.html')); });

With this setup, your backend can serve both your API at /api/... and your entire React application for all other routes. Note that this is one of several valid deployment strategies. Another popular approach is to deploy the frontend and backend to separate services (e.g., frontend to Vercel, backend to Render).


Activities

Activity 1: Live Demo & Configuration

Task: As a class, you will walk through the process of preparing a simple MERN application for a production build.

Steps Shown:

  1. Adding a build script to the client’s package.json.
  2. Creating a production .env.production file (for demonstration only) and adding it to .gitignore.
  3. Configuring the cors middleware in server.js to use an environment variable.
  4. Adding the express.static middleware and the catch-all route to server.js.
  5. Running npm run build in the client directory and inspecting the resulting build folder.

Summary

In this lesson, we contrasted IaaS and PaaS hosting models, identifying PaaS as a powerful choice for its ease of use in MERN deployments. You learned the essential steps to prepare an application for production: creating optimized frontend builds, securing the application by managing environment variables outside of your codebase, locking down CORS to a specific domain, and configuring the Express server to serve the React application. These steps are fundamental to transforming a local development project into a secure, stable, and performant application ready for the world.


Additional Resources