Sveltekit Node.js version update for Vercel deployment| Sabbirz | Blog

Upgrade Node.js version of the sveltekit project to deploy in Vercel

sveltekit node js version update for vercel production deployment

Sveltekit Node.js version update for Vercel deployment

svelte Dependency Conflict ERESOLVE svelte-kit Upgrade Guide vite svelte.config.js Vercel Tutorial web development Node.js Upgrade Troubleshooting npm Node.js Web Dev package-lock.json package.json

You get an email from your hosting provider, Vercel. It’s a routine notice: "Upgrade your Node.js version." It seems simple enough. But what follows is a cascade of cryptic error messages, dependency conflicts, and a project that works perfectly on your machine but fails spectacularly in the cloud.

This isn't a unique situation. It's a classic software development problem known as "Dependency Hell." We just navigated it, and this post breaks down what happened, why it happened, and how we escaped.

The Spark: A Simple Request

It all started with a clear goal: upgrade a SvelteKit project to use Node.js 22 on Vercel. The first step was updating our package.json.

"engines": {
  "node": "22.x"
}

This tells Vercel which Node.js version to use. But this one line was just the tip of the iceberg.

Problem 1: The Adapter's Complaint

The first deployment failed. The error was from SvelteKit's build system, specifically @sveltejs/adapter-auto.

Error: Unsupported Node.js version... Please use Node 16 or Node 18.

This was our first major clue. The issue wasn't Vercel; it was the SvelteKit adapter. The version we had didn't recognize "Node.js 22" as a valid runtime. The fix was to explicitly use @sveltejs/adapter-vercel and tell it which runtime to use in svelte.config.js.

Problem 2: The Cascade of Conflicts (ERESOLVE)

When we tried to install the new Vercel adapter, npm threw an ERESOLVE error. This is npm's way of saying, "I can't do what you're asking because it creates a contradiction."

Conflict #1: SvelteKit Version The new Vercel adapter required a newer version of SvelteKit (^2.0.0) than our project had (^1.5.0).

Conflict #2: Svelte Version Upgrading SvelteKit then revealed the next conflict. The new SvelteKit required Svelte 4 or 5, but our project was on Svelte 3.

Conflict #3: Vite Version Upgrading SvelteKit and Svelte then created another conflict. These new versions required Vite 5, but our project was on Vite 4.

Each time we tried to fix one dependency, another would break. We were trying to solve the puzzle one piece at a time, but the pieces were all interconnected.

Why Did This Happen? The "Stale Lockfile"

The core of the problem was our package-lock.json file. This file "locks" the exact versions of all your dependencies and sub-dependencies. It’s designed to ensure you and your teammates install the exact same package versions.

However, after our first few failed npm install attempts, this file and the node_modules folder became a messy, inconsistent state. npm was trying to resolve new packages against a backdrop of old, conflicting ones. It was trying to build a new puzzle using pieces from an old, different one.

The Solution: A Clean Slate

The final, successful strategy was to stop fixing and start fresh.

1. Deletion: We completely deleted the node_modules folder and the package-lock.json file. This removed the entire history of conflicts and gave npm a clean slate.

2. A Correct package.json: We manually edited the package.json file, providing a complete list of devDependencies that were all known to be compatible with each other (Svelte 4, SvelteKit 2, Vite 5, etc.).

The Old package.json

{
  "name": "ecom-analytics",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "dev": "vite dev",
    "build": "vite build",
    "preview": "vite preview",
    "test": "playwright test",
    "test:unit": "vitest",
    "lint": "prettier --plugin-search-dir . --check . && eslint .",
    "format": "prettier --plugin-search-dir . --write ."
  },
  "devDependencies": {
    "@playwright/test": "^1.28.1",
    "@sveltejs/adapter-auto": "^2.0.0",
    "@sveltejs/kit": "^1.5.0",
    "autoprefixer": "^10.4.14",
    "eslint": "^8.28.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-svelte": "^2.26.0",
    "postcss": "^8.4.23",
    "postcss-load-config": "^4.0.1",
    "prettier": "^2.8.0",
    "prettier-plugin-svelte": "^2.8.1",
    "svelte": "^3.54.0",
    "svelte-calendar": "^3.1.6",
    "svelte-preprocess": "^5.0.3",
    "tailwindcss": "^3.3.1",
    "vite": "^4.3.0",
    "vitest": "^0.25.3"
  },
  "type": "module",
  "dependencies": {
    "daisyui": "^2.51.6",
    "dotenv": "^16.0.3"
  }
}

The Updated package.json

{
  "name": "ecom-analytics",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "dev": "vite dev",
    "build": "vite build",
    "preview": "vite preview",
    "test": "playwright test",
    "test:unit": "vitest",
    "lint": "prettier --plugin-search-dir . --check . && eslint .",
    "format": "prettier --plugin-search-dir . --write ."
  },
  "engines": {
    "node": "22.x"
  },
  "devDependencies": {
    "@playwright/test": "^1.44.1",
    "@sveltejs/adapter-vercel": "^5.3.0",
    "@sveltejs/kit": "^2.5.10",
    "@sveltejs/vite-plugin-svelte": "^3.1.1",
    "autoprefixer": "^10.4.19",
    "eslint": "^8.57.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-svelte": "^2.39.0",
    "postcss": "^8.4.38",
    "postcss-load-config": "^5.0.3",
    "prettier": "^3.2.5",
    "prettier-plugin-svelte": "^3.2.3",
    "svelte": "^4.2.17",
    "svelte-preprocess": "^5.1.4",
    "tailwindcss": "^3.4.3",
    "vite": "^5.2.11",
    "vitest": "^1.6.0"
  },
  "type": "module",
  "dependencies": {
    "daisyui": "^2.51.6",
    "dotenv": "^16.0.3",
    "svelte-calendar": "^3.1.6"
  }
}

3. The Correct svelte.config.js: With the right packages ready to be installed, we configured SvelteKit to use the Vercel adapter and specify the Node.js 22 runtime. This file is crucial for the build process.

// svelte.config.js
import preprocess from "svelte-preprocess";
import adapter from "@sveltejs/adapter-vercel";

/** @type {import('@sveltejs/kit').Config} */
const config = {
  kit: {
    adapter: adapter({
      runtime: "nodejs22.x",
    }),
  },
  preprocess: [
    preprocess({
      postcss: true,
    }),
  ],
};

export default config;

4. Fresh Install: With a clean folder and valid configuration files, a simple npm install worked perfectly. npm was able to build a brand new, consistent package-lock.json from scratch without any conflicts.

Key Takeaways

  • ERESOLVE means stop and think. Don't use --force. It means there's a real contradiction in your dependencies.
  • Upgrades are rarely just one package. A major version change (like Node.js) often requires updating the entire toolchain (framework, build tool, plugins).
  • When in doubt, start fresh. If you are stuck in dependency hell, deleting node_modules and package-lock.json is often the fastest way out.
  • Know your ecosystem. Understanding that SvelteKit depends on Vite, and that adapters depend on SvelteKit, is key to diagnosing these issues.

What started as a simple version bump became a deep dive into project dependencies. By understanding the root cause, we can now approach future upgrades with a clearer strategy.