Deployment Guide
EduNest is one Next.js application, so deploying it is the same everywhere: build it, set your environment variables, point it at PostgreSQL, and serve it. There is no separate API process and no background daemon to manage. This guide covers the production build, environment configuration, the database, file storage, scheduled jobs, and license activation.
Choosing where to host? See the Hosting Guide for a side-by-side of Vercel, a Node VPS, and other options.
Building for Production
From the project root:
npm install # install dependencies
npm run build # produce the optimized production build
npm run start # serve it (defaults to port 3000)
npm run build runs next build; npm run start runs next start. On a managed platform such as Vercel, the build and start commands are configured for you (see the bundled vercel.json).
The database client is lazy-initialised —
DATABASE_URLis only read at request time, not at build time. This meansnext buildsucceeds even if the database is not reachable during the build step. Make sureDATABASE_URLis present at runtime.
Environment Variables in Production
Set the same variables documented in the Installation Guide in your host's environment configuration. The essentials for a live deployment:
DATABASE_URL="postgresql://user:password@host/dbname?sslmode=require"
JWT_SECRET="a-long-random-string"
SECRET_KEY="a-long-random-string" # encrypts stored integration secrets
NEXT_PUBLIC_SITE_URL="https://your-domain.com"
CRON_SECRET="a-random-string" # protects /api/v1/cron
Optional, depending on what you use: JWT_EXPIRES_IN, LICENSE_SERVER_URL / LICENSE_PUBLIC_KEY, ADMIN_EMAIL / ADMIN_PASSWORD, NOTIFY_EMAIL, API_DOCS_USER / API_DOCS_PASS, the R2_* storage fallbacks, PEXELS_API_KEY, and WORLDVECTORLOGO_API_KEY.
Generate strong secrets. Use something like
openssl rand -base64 48forJWT_SECRET,SECRET_KEY, andCRON_SECRET. If you changeSECRET_KEYafter integration credentials have been saved, those encrypted values can no longer be decrypted — set it once, before connecting integrations.
Database (Neon / PostgreSQL)
EduNest talks to PostgreSQL through the @neondatabase/serverless driver using raw SQL. The recommended database is Neon because the serverless driver is built for it and works over HTTP, which suits serverless hosts.
- Create a Neon project and copy its connection string into
DATABASE_URL. - The schema is created idempotently — by the
/installwizard, bynpm run db:init, or by theensure*()helpers at runtime. There is no migration framework to run on each deploy. - Any Neon-compatible PostgreSQL endpoint that the serverless driver accepts will work.
File Storage (Cloudflare R2)
Uploads — course media, images, certificates, attachments — go to object storage, never to local disk in production.
Critical for serverless hosts: on Vercel the application filesystem is read-only at runtime. The app detects this (the
VERCELenvironment variable is set automatically). Uploads must be sent to R2 (or another S3-compatible bucket); they cannot be written to the local filesystem. Configure storage before going live or uploads will fail.
EduNest's storage layer supports any S3-compatible provider — Cloudflare R2, DigitalOcean Spaces, Amazon S3, and Google Cloud Storage — through a single S3 client. Configure it one of two ways:
- Recommended — Admin → Settings → Integrations → Storage. Add your provider connection (endpoint, access key, secret, bucket, public URL) and mark it Active + Default. Credentials are encrypted in the database with
SECRET_KEY. - Fallback — environment variables. Set
R2_ENDPOINT,R2_ACCESS_KEY_ID,R2_SECRET_ACCESS_KEY,R2_DEFAULT_BUCKET, andR2_PUBLIC_URL. These are used only when no active storage connection exists in the database.
To set up Cloudflare R2:
- Create an R2 bucket and a public access URL (custom domain or
r2.dev). - Generate an R2 API token with read/write access.
- Paste the Account-specific endpoint, access key, secret, bucket name, and public URL into the admin (or the
R2_*env vars).
Scheduled Jobs (Cron)
Background tasks — payouts, reminders, cleanup — run via a single HTTP endpoint, /api/v1/cron, protected by CRON_SECRET.
On Vercel: the bundled
vercel.jsondeclares the cron for you:{ "crons": [ { "path": "/api/v1/cron", "schedule": "0 * * * *" } ] }No extra action is needed — Vercel calls it hourly automatically.
Self-hosted: add a crontab entry that curls the endpoint hourly. The install wizard's finish step prints the exact line, for example:
0 * * * * curl -fsS "https://your-domain.com/api/v1/cron?key=YOUR_CRON_SECRET" >/dev/null 2>&1
License Activation on the Live Domain
EduNest's license is tied to your production domain.
- On a local or LAN host (localhost,
127.0.0.1,*.localhost,*.test, private10.x/192.168.x/172.16–31.xranges) the app runs in dev mode — the license check is bypassed and all entitlements are unlocked, so you can build and test freely. - On your live domain, activate your purchase code. You can do this during the install wizard's license step, or later from the admin. Activation verifies against
LICENSE_SERVER_URL(defaulthttps://creative-cape.com) using an RS256 public key (a default is baked in; override withLICENSE_PUBLIC_KEYonly if instructed).
Because dev hosts bypass licensing, always verify entitlement-gated add-ons on your real domain before launch. See the License Guide for details.
Deployment Checklist
-
DATABASE_URLset and reachable at runtime -
JWT_SECRETandSECRET_KEYset to strong, stable values -
NEXT_PUBLIC_SITE_URLset to your live URL - Storage (R2 / S3) configured — required on read-only hosts
-
CRON_SECRETset and the hourly cron wired up - License activated on the live domain
- Admin password changed from any seed value
© CreativeCape Solutions · creative-cape.com · support@creative-cape.com