Upgrade Guide

EduNest LMS is a single Next.js application with raw-SQL PostgreSQL access and no migration tool. Schema is created and evolved idempotently by ensure*() functions (CREATE TABLE IF NOT EXISTS + CREATE INDEX IF NOT EXISTS), so most upgrades are: drop in the new source, install, build, and let the app create any new tables or indexes on its own. This guide walks through a safe upgrade end to end.

Table of Contents

Before You Upgrade

Never upgrade without a backup. Take a database backup and (if media changed) a copy of your uploads — see the Backup & Restore guide.

Terminal
# Full database snapshot (schema + data)
pg_dump "$DATABASE_URL" --format=custom --file=pre-upgrade-$(date +%Y%m%d).dump

On Neon you can also create a branch as an instant pre-upgrade snapshot:

Terminal
neonctl branches create --name pre-upgrade --parent main

Preserve your existing .env files — especially SECRET_KEY and JWT_SECRET. Changing SECRET_KEY makes previously-encrypted integration credentials unreadable, and changing JWT_SECRET logs everyone out.

Upgrade Steps

1. Get the new release

Download the latest EduNest LMS package from your CreativeCape / marketplace downloads.

2. Replace the source

Unpack the new release over your project, keeping your .env files (and any local config you customized). If you use git, commit your current state first so you can diff and roll back.

3. Install dependencies

Terminal
npm install

4. Apply schema changes

New tables and indexes are created idempotently. Run the initializer — it is safe to re-run on an existing database:

Terminal
npm run db:init

This runs the core, vendor, and LMS schema initializers (scripts/init-db.ts, init-vendor.ts, init-lms.ts). Every statement is CREATE TABLE IF NOT EXISTS / CREATE INDEX IF NOT EXISTS / additive ALTER ... IF NOT EXISTS, so it only adds what's missing and never drops your data. (Many ensure*() helpers also run automatically on first use, but running db:init makes the new schema available immediately and deterministically.)

5. Re-bundle add-ons (if changed)

If the release ships new or updated add-ons, regenerate the bundles and catalog:

Terminal
npm run addons:bundle
npm run addons:catalog

6. Build & redeploy

Terminal
npm run build
npm run start      # or trigger your platform's deploy (e.g. Vercel)

Upgrade checklist

Step Command / Action
Download CreativeCape downloads
Back up pg_dump (+ Neon branch, uploads)
Replace source Unpack over project, keep .env
Install deps npm install
Apply schema npm run db:init
Re-bundle add-ons npm run addons:bundle / addons:catalog (if changed)
Build npm run build
Deploy npm run start / platform deploy

How Schema Changes Are Applied

EduNest has no migration files and no migration command (no Prisma, no SQL migration tool). Instead, schema lives in ensure*() functions inside src/lib/*-schema.ts (e.g. lms-schema.ts, vendor-schema.ts, auth-schema.ts). Each uses idempotent DDL:

TS
await sql`CREATE TABLE IF NOT EXISTS sections (...)`;
await sql`CREATE INDEX IF NOT EXISTS idx_sections_course ON sections(course_id)`;

Consequences for upgrades:

  • New tables/columns/indexes in a release appear in these functions and are created the next time db:init (or the relevant ensure* path) runs — automatically, additively, non-destructively.
  • No manual migration step is required for additive changes.
  • Idempotent DDL means re-running db:init is always safe; existing objects are skipped.

Because there is no migration history, destructive changes (renaming/removing a column, backfilling data) cannot be expressed as idempotent IF NOT EXISTS DDL. If a release requires one, it will be called out explicitly in the changelog with the exact step to run — perform it manually after backing up.

Add-ons

Add-ons are packaged from source by build scripts rather than pulled at runtime:

  • npm run addons:bundle — bundles add-on packages (scripts/bundle-addons.mjs).
  • npm run addons:catalog — regenerates the add-on catalog (scripts/gen-addon-catalog.mjs).

Re-run these only when an upgrade changes the add-on set. Premium add-on entitlements are governed by your license (see the Security Guide) and are unlocked automatically on a licensed (or dev) host — upgrading the source does not change your entitlements.

Environment Variables

If a release introduces a new environment variable, add it to your .env before building. The variables the app reads include DATABASE_URL, JWT_SECRET, JWT_EXPIRES_IN, SECRET_KEY, CRON_SECRET, API_DOCS_USER / API_DOCS_PASS, LICENSE_SERVER_URL, LICENSE_PUBLIC_KEY, and the R2_* storage fallbacks. The database connection is lazy (read at request time), so a missing DATABASE_URL won't break next build — but the app will fail at runtime until it's set.

Rollback

If an upgrade goes wrong:

  1. Restore the database from your pre-upgrade dump (or switch DATABASE_URL back to the Neon pre-upgrade branch):

    Terminal
    pg_restore --clean --if-exists --no-owner --dbname="$DATABASE_URL" pre-upgrade-20260626.dump
    
  2. Redeploy the previous release source, run npm install and npm run build for that version.

  3. Restore uploads only if media paths/format changed during the upgrade.

Because additive IF NOT EXISTS DDL never drops data, rolling the source back is usually enough; the extra columns/tables the newer version added simply go unused by the older code.

Versions & Changelog

The package version is recorded in package.json ("version"). Read the release changelog from your current version up to the target version before a major upgrade, and apply any explicitly-flagged manual steps (destructive schema changes, new required env vars) in order. When upgrading across several versions at once, review every intermediate changelog entry.

Need help with an upgrade? Contact support@creative-cape.com with your current and target version numbers.


© CreativeCape Solutions · creative-cape.com · support@creative-cape.com