Skip to content

Running Intro to AI Engineering locally ​

Use this page to run the extracted Gift Genie project from Intro to AI Engineering on your computer with your own AI provider. The project comes in two forms: a browser-only Vite app in the lessons before the backend migration, and an Express and Vite app from the backend migration onward. One line in package.json tells you which you have; the install and the .env file are the same for both, and the start differs.

What you need first ​

Install a supported LTS version of Node.js. Node 24 is recommended and includes npm.

Check that both commands work. Your version numbers may be different:

bash
$ node --version
v24.18.0
$ npm --version
11.18.0

You also need the three values you set in Scrimba's environment variables during the course: your provider's URL, your API key, and the model ID. If you no longer have the key, create a new one at the same provider.

JunoWhat you need first Install the LTS version of Node.js, which includes npm, and check that node --version and npm --version both print a version.

Then have your provider's URL, your API key and your model ID ready. You'll paste all three into one file in a few minutes.

JunoWhat you need first The three values work as a set: the URL picks the provider, the key proves who you are to that provider, and the model ID names one of its models. A key from one provider sent to another provider's URL is turned down.
JunoWhat you need first Both forms of the project use Vite 7.3, which needs Node 20.19 or 22.12 and newer. Node 20 has reached end of life, so in practice that means Node 22.12 or a newer LTS.

Find out which project you have ​

Open package.json in the extracted folder and find the start line. If it says only vite, you have the browser-only project:

json
"start": "vite"

If it says concurrently, with a server script under it, you have the backend project. Its folder also holds server.js:

json
"start": "concurrently \"npm run client\" \"npm run server\" ",
"server": "node --watch server.js",
JunoFind out which project you have Open package.json and read the start line. If it says vite and nothing else, you have the browser-only project. If it says concurrently, you have the backend project.

Remember which one: the last two sections each cover one of them.

JunoFind out which project you have The start script is what runs when you type npm start. The browser-only project runs Vite alone; the backend project runs Vite and an Express server side by side from one command.
JunoFind out which project you haveconcurrently starts npm run client and npm run server as two child processes and prefixes their output with [0] and [1], so Vite's lines and Express's lines share one terminal.

Install the packages ​

Open a terminal in the extracted folder, the one containing package.json. Every command on this page runs from there:

bash
$ cd path-to-your-extracted-project

Install the packages the project lists. This is the same for both forms:

bash
$ npm install

npm finishes by reporting how many packages it added. It may also report vulnerabilities, or allow-scripts warnings about esbuild and fsevents. Neither stops the project from running.

JunoInstall the packages Run npm install in the folder with package.json. It ends by saying how many packages it added.

If npm says it cannot find package.json, you are in the wrong folder.

JunoInstall the packages The download includes package-lock.json, so npm installs the same package versions the course used. The vulnerability count describes those versions; it is not a sign that the install failed.
JunoInstall the packages Newer npm releases list packages whose install scripts have not been approved. Vite still starts without approving them here, because esbuild's binary arrives as a platform package rather than through that script.

Add your values to .env ​

On Scrimba, the editor fills in your three environment variables for you. On your computer, they come from a file. Create .env beside package.json and put your values in it under exactly these names:

dotenv
AI_URL=https://api.openai.com/v1
AI_KEY=your-key-here
AI_MODEL=your-model-id

This example uses OpenAI's URL. If you used another provider in the course, such as Groq or OpenRouter, use its URL instead. The model ID must be one that provider offers.

Create .gitignore beside package.json and add:

txt
.env
node_modules/

A key that reaches a Git repository stays in its history even after you delete the file. The Git handbook covers the habit in ignoring files and good habits.

Never commit your API key

.env holds a working key. Don't upload it, paste the key into your code, or commit the file. If a key is ever exposed, delete it at your provider and create a new one.

JunoAdd your values to .env Make a file called .env next to package.json with your three values, one per line, then list .env in .gitignore so Git never saves it.
JunoAdd your values to .env Both projects watch .env while they run. Save it and Vite prints .env changed, restarting server...; in the backend project the server also prints Restarting 'server.js'. Reload the page and the new values are in use.
JunoAdd your values to .env The two forms read the same file in different places. The browser-only project's vite.config.js loads it with loadEnv; the backend project loads it into Node with a start flag you add in its own section. The backend's Vite config still reads .env, but never puts the key in the page.

Run the browser-only project ​

This version puts your key in the browser

These lessons call the AI provider straight from the page, so Vite writes AI_KEY into the code it sends to the browser, and anyone who opens the page can read it. Use a key you will delete when you are done, keep this version on your own computer, and never deploy or share it. The backend migration later in the course moves the key onto a server.

Start the project:

bash
$ npm start

Vite prints the address to open:

text
  VITE v7.3.0  ready in 176 ms

  ➜  Local:   http://localhost:5173/

Open the exact Local address. If port 5173 is busy, Vite picks the next one and prints that instead.

In the early lessons, such as Setting Up Your AI Client, the page is blank on purpose: the work happens in the browser console. Open your browser's developer tools (F12, or Cmd+Option+J in Chrome on a Mac) and read the Console tab. It should show your values:

text
AI provider URL: https://api.openai.com/v1
AI model: your-model-id

Lessons that build the Gift Genie page show that page instead. Stop the project with Ctrl+C.

JunoRun the browser-only project Run npm start and open the Local address. If the page is blank, open the Console: the two lines with your provider URL and model mean .env was read.

A red Missing AI_URL there means it was not.

JunoRun the browser-only projectutils.js checks the three values as soon as the page loads and throws on the first one that is missing. The console lines are that check passing; they say nothing yet about whether the provider accepts the key.
JunoRun the browser-only projectvite.config.js uses define to replace each process.env.AI_KEY, AI_URL and AI_MODEL in your code with the value from .env while it serves the page. That replacement is how the key ends up in every browser that loads it.

Run the backend project ​

On Scrimba, the server got your environment variables automatically. On your computer, Node reads .env only when you tell it to, and the server script in the download does not. So make one change in package.json before you start. Change the server script from:

json
"server": "node --watch server.js",

to:

json
"server": "node --env-file=.env --watch server.js",

Then start both parts of the app:

bash
$ npm start

The [1] lines come from the Express server and the [0] lines from Vite:

text
[1] Server running at http://localhost:3001
[0]
[0]   VITE v7.3.1  ready in 1526 ms
[0]
[0]   ➜  Local:   http://localhost:5173/

Open the Vite Local address, not port 3001: the server answers only the app's /api requests, so port 3001 on its own shows Cannot GET /. Type who the gift is for and click Rub the Lamp. The button changes to Summoning Gift Ideas..., and a few seconds later gift ideas appear under it. That means your key, URL and model all work.

If the page says Sorry, I can't access what I need right now, the reason is in the terminal, on a [1] line from the server. The troubleshooting below matches each message.

Stop both parts with one Ctrl+C. When you save .env while the app runs, both parts restart by themselves and use the new values.

The Deployment project needs the same --env-file change for its server.

JunoRun the backend project Add --env-file=.env to the server script, run npm start, and open the Vite Local address. Click Rub the Lamp and wait for the gift ideas.

If the page apologizes instead, read the newest [1] lines in the terminal.

JunoRun the backend project The page sends its request to /api/gift on the Vite address. Vite forwards every /api request to Express on port 3001, and Express calls the provider with the key it read from .env. The browser never sees the key.
JunoRun the backend project The proxy target in vite.config.js is fixed at http://localhost:3001, while server.js listens on PORT or 3001. Leave PORT out of .env and the two agree, unless your terminal already sets PORT, which wins over .env. Whenever the server lands on another port, the proxy target must change to match.

Troubleshooting ​

Browser-only: a blank page, and the console says Missing AI_URL, Missing AI_MODEL or Missing AI_KEY: Vite did not find that value. Check that .env is beside package.json and that the names are spelled exactly as above, then save it. Vite restarts by itself (.env changed, restarting server...); reload the page.

Backend: the terminal says Missing credentials, then Failed running 'server.js': The server started without your .env. Check that the server script contains --env-file=.env and that .env spells AI_KEY exactly, then stop the project with Ctrl+C and run npm start again.

Backend: the terminal says node: .env: not found: The flag is in place, but there is no .env beside package.json. Create it there, or check that your editor did not save it as .env.txt. The server has already stopped, so stop the project with Ctrl+C and run npm start again.

Backend: the page says Sorry, I can't access what I need right now, and the terminal shows 401 with Incorrect API key provided: The request reached your provider, which did not accept the key. Copy the key again, and check that the URL in AI_URL belongs to the same provider.

Your provider says the model does not exist or is not available: The message shows on a [1] line in the terminal for the backend project, or in the browser console for a browser-only lesson that sends a request. Copy the model ID again exactly as your provider lists it, and check that it belongs to the provider in AI_URL.

Backend: the terminal shows http proxy error: /api/gift with ECONNREFUSED: Vite cannot reach Express on port 3001. Scroll up to the first [1] lines. If they show an error, the server stopped there, usually for one of the reasons above. If they say Server running at a port other than 3001, your terminal already sets PORT, which wins over .env: change the proxy target in vite.config.js to that port.

Backend: EADDRINUSE mentions port 3001: Another program is using the server's port. Stop it, or set PORT in .env and change the proxy target in vite.config.js to the same port.

npm start says concurrently: command not found or vite: command not found: The packages are not installed in this folder. Run npm install in the folder that contains package.json.

JunoTroubleshooting Find the first error and match it to a bold heading above. In the browser-only project, look in the browser's Console; in the backend project, look in the terminal.
JunoTroubleshooting Keep three problems apart: .env not being read, a process not running, and the provider turning down the key or model. They fail in that order, and the first two never reach the provider at all.
JunoTroubleshooting A 401 means the whole chain worked up to the provider: the page, the proxy, Express and --env-file. A missing-credentials error comes from the OpenAI client's constructor, so the server stops before it listens on any port.