The MEAN stack is MongoDB, Express, Angular and Node.js: one language, JavaScript (usually TypeScript), from the database query to the button on the screen. This handbook explains what each part does, sets up a current 2026 project, builds a small API and Angular front end, covers security and testing, and shows where a finished MEAN app can actually run on Domain India.
Use the current Node.js LTS (24), Express 5, MongoDB 8 with Mongoose, and a current Angular release with standalone components and signals. Keep the API on its own port, call it from Angular through a proxy in development, and serve the Angular build as static files in production. Store sessions in httpOnly cookies, not localStorage. A full MEAN app with its own MongoDB belongs on a VPS; shared hosting can't reach MongoDB.
1. What each part does
| Layer | Technology | Its job |
|---|---|---|
| Database | MongoDB (with Mongoose) | Stores data as JSON-like documents |
| API | Express on Node.js | Receives HTTP requests, checks input and users, reads and writes the database |
| Runtime | Node.js | Runs JavaScript on the server |
| Interface | Angular | Builds the pages and components in the browser |
A request flows like this: an Angular component calls /api/products, Express checks the user and the input, Mongoose queries MongoDB, and the result goes back to Angular as JSON.
- Teams that want one language, and TypeScript, across the whole app
- Business dashboards, admin tools and larger single-page apps
- Data whose shape changes as the product grows
- The data is strongly relational (accounts, invoices, stock): PostgreSQL or MySQL fits better
- Every page must be indexed by search engines: plan for Angular's server-side rendering
- The site is mostly content: a CMS is simpler
2. Set up your machine
- Install Node.js LTS.Use nvm so you can switch versions:
nvm install --lts. In 2026 the active LTS is Node.js 24; Node.js 20 reached end of life in April 2026. See working with Node.js versions using nvm. - Install the Angular CLI.
npm install -g @angular/cli, then check withng version. - Get a MongoDB for development.Run it locally in Docker, bound to your own machine:
docker run -d --name mongo -p 127.0.0.1:27017:27017 mongo:8.0. A free MongoDB Atlas cluster also works for development. - Use Git from the first commit.
3. Project layout
Keep the API and the front end in separate folders of one repository:
shop/
api/ Express + Mongoose
web/ Angular (ng new web)Create the API:
mkdir -p shop/api && cd shop/api
npm init -y
npm pkg set type=module scripts.start="node server.js"
npm install express mongooseCreate the front end from the shop folder with ng new web. New projects use standalone components by default; there are no NgModules to write.
4. Build the API
Node.js 24 reads .env files natively, so secrets stay out of your code. api/.env:
PORT=4000
MONGODB_URI=mongodb://127.0.0.1:27017/shopapi/server.js:
import express from 'express';
import mongoose from 'mongoose';
process.loadEnvFile('.env');
await mongoose.connect(process.env.MONGODB_URI);
const Product = mongoose.model('Product', new mongoose.Schema({
name: { type: String, required: true, trim: true, maxlength: 120 },
price: { type: Number, required: true, min: 0 }
}, { timestamps: true }));
const app = express();
app.use(express.json({ limit: '100kb' }));
app.get('/api/products', async (_req, res) => {
res.json(await Product.find().sort({ createdAt: -1 }).limit(50).lean());
});
app.post('/api/products', async (req, res) => {
const { name, price } = req.body;
const product = await Product.create({ name, price });
res.status(201).json(product);
});
app.use((err, _req, res, _next) => {
const status = err.name === 'ValidationError' ? 400 : 500;
res.status(status).json({ error: status === 400 ? err.message : 'Server error' });
});
app.listen(process.env.PORT, '127.0.0.1', () => console.log('API ready'));Express 5 passes errors thrown in async handlers to the error handler, so no wrapper is needed. The API picks only the fields it expects from req.body and lets the schema validate them. In a real app, protect the POST route with the sign-in check from section 6. Run it with npm start and test with curl http://127.0.0.1:4000/api/products.
5. Build the Angular front end
Point Angular's development server at the API with web/proxy.conf.json:
{ "/api": { "target": "http://127.0.0.1:4000", "secure": false } }Start it with ng serve --proxy-config proxy.conf.json. Add provideHttpClient() to the providers in app.config.ts, then a component that loads products into a signal:
import { Component, inject, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';
type Product = { _id: string; name: string; price: number };
@Component({
selector: 'app-products',
template: `
@for (p of products(); track p._id) {
<p>{{ p.name }}: ₹{{ p.price }}</p>
} @empty { <p>No products yet.</p> }
`
})
export class ProductsComponent {
private http = inject(HttpClient);
products = signal<Product[]>([]);
constructor() {
this.http.get<Product[]>('/api/products').subscribe(list => this.products.set(list));
}
}Because the browser calls /api on the same origin, you need no CORS setup in development, and in production Nginx routes /api to Express the same way.
6. Authentication and security
- Passwords: hash with bcrypt or Argon2id. Never store or log a plain password.
- Sessions: put a signed token in an httpOnly, Secure, SameSite cookie with a short lifetime. Keep the signing secret in an environment variable generated with
openssl rand -base64 64, never in code. Don't keep tokens in localStorage, where any injected script can read them. - Rate limiting: limit login and password-reset routes.
- Input: accept only the fields you expect, and never pass
req.bodystraight into a MongoDB query, which allows operator injection such as{ "$gt": "" }.
The complete login, logout, route guard and password-reset code is in developing the user authentication service in the MEAN stack.
7. Testing and debugging
| Level | Tool in 2026 | Notes |
|---|---|---|
| Angular unit tests | Vitest, the default for new Angular projects | Karma is deprecated |
| API tests | Node's built-in test runner or Vitest, with Supertest | Test routes against a throwaway database |
| End-to-end | Playwright or Cypress | Protractor is discontinued; don't use it |
| Debugging | Browser DevTools, node --inspect | VS Code attaches to both |
Add a MongoDB index for every field you filter or sort on, for example schema.index({ createdAt: -1 }), and check slow queries with .explain().
8. Deploy: where a MEAN app can run
A MEAN app has three parts to host: static Angular files, a long-running Express process and a MongoDB database.
| Option | Fits MEAN? | What to know |
|---|---|---|
| Domain India VPS | Yes, fully | Run Nginx, the API under PM2 or systemd, and MongoDB on 127.0.0.1. Full root access, self-managed |
| Domain India App Platform | The API, yes | Node.js is detected automatically; the included database is PostgreSQL, so MongoDB must be an external service reachable from your app (test it). WebSockets are not supported |
| Shared hosting (cPanel, DirectAdmin) | Partly | The Angular build runs as static files, and the Node.js tool can run an API, but MongoDB is not available from shared hosting |
On a VPS, run ng build, copy web/dist/web/browser to /var/www/shop, run the API with PM2 on 127.0.0.1:4000, and let Nginx serve the files and proxy /api/. The full, tested setup, including MongoDB with authentication, Certbot and start on boot, is in running MERN or MEAN on a clean VPS.
On shared hosting, only an Angular front end that talks to an API hosted elsewhere, or an Express API that uses MySQL instead of MongoDB, is practical. See deploying a Node.js app on shared hosting.
Socket.IO and other WebSocket features need a long-lived connection. Run them on a VPS behind Nginx with the Upgrade headers set. The App Platform does not support WebSockets.
9. Where Domain India fits
For a complete MEAN app with its own database, a self-managed VPS is the natural home. Choose no control panel at checkout.
- 1 vCPU
- 2 GB DDR4 RAM
- 64 GB NVMe SSD Storage
- 2 TB Monthly Bandwidth
If you would rather not run a server, the App Platform can host the Express API, with MongoDB on an external service.
- 512 MB RAM per app
- 1 vCPU
- 5 GB NVMe SSD
- PostgreSQL Database
Prices on the cards are live Domain India list prices and exclude 18% GST.
Frequently asked questions
What does MEAN stand for?
MongoDB, Express, Angular and Node.js. MongoDB stores the data, Express on Node.js provides the API, and Angular builds the user interface in the browser, all in JavaScript or TypeScript.
Which versions should I use for a MEAN app in 2026?
The current Node.js LTS (24), Express 5, MongoDB 8 with a current Mongoose, and a current Angular release with standalone components and signals. Node.js 20 reached end of life in April 2026.
Can I host a MEAN stack app on Domain India shared hosting?
Not completely. The Angular build can be served as static files and the Node.js tool can run an API, but MongoDB is not available from shared hosting. For a full MEAN app, use a VPS.
Can the Domain India App Platform run a MEAN app?
It can run the Express API, because Node.js apps are detected automatically. Its included database is PostgreSQL, so MongoDB has to be an external service your app can reach. WebSockets are not supported.
Where should I store the login token in Angular?
In an httpOnly, Secure, SameSite cookie set by the API, not in localStorage. Angular then sends the cookie with each request and never handles the token itself.
Is Protractor still used for Angular end-to-end tests?
No. Protractor is discontinued. Use Playwright or Cypress for end-to-end tests. For unit tests, new Angular projects use Vitest, and Karma is deprecated.
Ready to ship your MEAN app? Compare VPS plans, look at the App Platform for the API, or open a ticket if you are unsure which fits your project.
A self-managed KVM VPS with full root access, ready for Node.js, MongoDB and Nginx.
See VPS plans