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
- Upgrade Steps
- How Schema Changes Are Applied
- Add-ons
- Environment Variables
- Rollback
- Versions & Changelog
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.
# 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:
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
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:
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:
npm run addons:bundle
npm run addons:catalog
6. Build & redeploy
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:
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 relevantensure*path) runs — automatically, additively, non-destructively. - No manual migration step is required for additive changes.
- Idempotent DDL means re-running
db:initis 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 EXISTSDDL. 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:
Restore the database from your pre-upgrade dump (or switch
DATABASE_URLback to the Neon pre-upgrade branch):pg_restore --clean --if-exists --no-owner --dbname="$DATABASE_URL" pre-upgrade-20260626.dumpRedeploy the previous release source, run
npm installandnpm run buildfor that version.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