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:

Terminal
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-initialisedDATABASE_URL is only read at request time, not at build time. This means next build succeeds even if the database is not reachable during the build step. Make sure DATABASE_URL is 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:

ENV
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 48 for JWT_SECRET, SECRET_KEY, and CRON_SECRET. If you change SECRET_KEY after 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 /install wizard, by npm run db:init, or by the ensure*() 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 VERCEL environment 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:

  1. 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.
  2. Fallback — environment variables. Set R2_ENDPOINT, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_DEFAULT_BUCKET, and R2_PUBLIC_URL. These are used only when no active storage connection exists in the database.

To set up Cloudflare R2:

  1. Create an R2 bucket and a public access URL (custom domain or r2.dev).
  2. Generate an R2 API token with read/write access.
  3. 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.json declares the cron for you:

    JSON
    { "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:

    Terminal
    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, private 10.x / 192.168.x / 172.16–31.x ranges) 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 (default https://creative-cape.com) using an RS256 public key (a default is baked in; override with LICENSE_PUBLIC_KEY only 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_URL set and reachable at runtime
  • JWT_SECRET and SECRET_KEY set to strong, stable values
  • NEXT_PUBLIC_SITE_URL set to your live URL
  • Storage (R2 / S3) configured — required on read-only hosts
  • CRON_SECRET set 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