The LMS Backend reads all runtime configuration from aDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Pragyat-Nikunj/Learning-Management-System-backend/llms.txt
Use this file to discover all available pages before exploring further.
.env file in the project root. The server will not start without a valid MongoDB URI, and payment and media features will fail silently if their respective keys are missing. Create the file before running npm run dev.
Full .env template
Copy this template into a file named.env at the project root and fill in every value:
.env
Variable reference
Server
The port the Express server listens on. The README and all curl examples in this documentation use
4000. Must match the port you target in your frontend’s API base URL.Runtime environment. Set to
development to enable Morgan HTTP request logging and Mongoose query debugging. Set to production to disable both and suppress stack traces from error responses.The origin of your frontend application, used to configure CORS. The server allows credentials (cookies) only from this origin. Defaults to
http://localhost:5173 if not set. Update this to your deployed frontend URL in production.Database
The full MongoDB connection string. Use
mongodb://localhost:27017/lms for a local instance or a MongoDB Atlas connection string for a hosted cluster. The database layer retries the connection up to three times on failure before exiting.The README documents this variable as
DATABASE_URL, but the actual code in databases/db.js reads process.env.MONGO_URI. Use MONGO_URI in your .env file.Authentication
The secret used to sign and verify JWT tokens. Read by
auth.middleware.js via jwt.verify(token, process.env.SECRET_KEY). Use a random string of at least 32 characters. Any change to this value invalidates all existing sessions immediately.Cloudinary (media uploads)
Course thumbnails and lecture videos are uploaded to Cloudinary. All three variables are required for the upload and delete functionality used by the course and user profile endpoints.Your Cloudinary cloud name, visible in the Cloudinary dashboard under Settings → Account.
Your Cloudinary API key. Found alongside the cloud name in the Cloudinary dashboard.
Your Cloudinary API secret. Treat this like a password — it authorizes server-side upload and delete operations.
Stripe
Your Stripe secret API key. Used server-side to create Checkout sessions. Use a
sk_test_... key during development and a sk_live_... key in production. Never expose this key to the client.The signing secret for your Stripe webhook endpoint. Stripe signs every event payload it sends to The CLI prints the webhook signing secret (
POST /api/v1/payments/webhook. The server uses this secret to verify the signature and reject spoofed requests.To get this value during local development, use the Stripe CLI:whsec_...) when it starts. Copy it into your .env.Razorpay
Your Razorpay key ID. Used to authenticate Razorpay API requests. Begins with
rzp_test_ in test mode and rzp_live_ in production.Your Razorpay key secret. Used together with the key ID to authenticate server-side Razorpay calls. Treat this with the same care as your Stripe secret key.
Security notes
- Set
NODE_ENV=productionon any internet-facing deployment. This suppresses stack traces from the global error handler, which prevents internal file paths and error details from leaking to clients. - Generate
SECRET_KEYwith a cryptographically secure random generator, for example:node -e "console.log(require('crypto').randomBytes(32).toString('hex'))". - The global rate limiter allows 100 requests per IP per 15-minute window on all
/apiroutes. AdjustwindowMsandlimitinindex.jsif your use case requires different thresholds.