Skip to content

Running the Vercel AI SDK course locally ​

Use this page to run the extracted customer-support agent from the Vercel AI SDK course on your computer and get an answer with your own OpenAI key and the Supabase project you built in the course. One Node server runs the whole project: it serves the chat page and answers its questions, so your keys stay on that server and never reach the browser. One thing differs from Scrimba's editor: Node does not read .env on its own, so the start script needs one flag.

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 three values:

  • an OpenAI API key, on an account with billing set up, because OpenAI writes every answer;
  • your Supabase project URL, shown in the project's Connect dialog;
  • that project's secret key, which starts with sb_secret_, from Settings > API Keys.

Use the Supabase project from the course. The agent searches the Scrimba help documents stored there through the project's match_documents function. If you no longer have that project, the server still needs a Supabase URL and secret key to start, and a new project's values will do. Only Scrimba questions use Supabase, so general questions still get answers from web search, while Scrimba questions find nothing to search.

The legacy service_role key also works until Supabase retires it, planned for the end of 2026. See Supabase API keys.

JunoWhat you need first Check that node --version and npm --version both print a version. Then collect three things: your OpenAI key, your Supabase project URL, and that project's secret key.

Use the Supabase project you built in the course; a new one has no documents for the agent to search.

JunoWhat you need first Billing matters because every question costs OpenAI requests. A general question takes one: the model searches the web and answers in the same request. A Scrimba question takes three: one to choose the knowledge base, one to turn the question into an embedding for Supabase, and one to write the answer.
JunoWhat you need firstconfig.js builds the Supabase client with the secret key, so the match_documents call skips Row Level Security entirely. That is safe only because the client exists on the server; Supabase also rejects a secret key sent from a browser.

Install the packages ​

Open a terminal in the extracted folder, the one containing package.json and server.js, and install the exact package versions the course used:

bash
$ cd path-to-your-extracted-project
$ npm ci
added 94 packages, and audited 95 packages in 4s

npm also reports some vulnerabilities in those packages. They don't stop the project from running on your computer. Don't run npm audit fix; it upgrades packages the course code was written against.

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

If npm says it can only install with an existing package-lock.json, you are in the wrong folder.

JunoInstall the packagesnpm ci installs from package-lock.json, not from the ranges in package.json, so you get the AI SDK, Supabase client and Express versions the course used rather than the newest ones the ranges allow.
JunoInstall the packagespackage.json asks for ai ^5.0.29; the lockfile pins 5.0.43, with @ai-sdk/openai 2.0.30. npm ci refuses to run when the two files disagree, so an edited dependency fails here, not halfway through a question.

Change the start script ​

In Scrimba, the editor handed your keys to the server. On your computer, Node reads .env only when you ask it to, and config.js stops the server at once if the OpenAI key is missing. Open package.json and change the start script from:

json
"start": "node server.js"

to:

json
"start": "node --env-file=.env server.js"

The flag is built into Node, so there is nothing extra to install.

JunoChange the start script In package.json, add --env-file=.env to the start script exactly as shown, and save the file. Nothing else in the project changes.
JunoChange the start script With the flag, Node copies each line of .env into process.env before server.js runs, which is where config.js looks for the keys. Without it, the first check in config.js stops the server.
JunoChange the start script A variable already set in your shell wins over the same name in .env. An old OPENAI_API_KEY exported in your terminal profile is used instead of the one in the file.

Add your keys to .env ​

Create .env beside package.json with your three values:

dotenv
OPENAI_API_KEY=your-openai-api-key
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your-supabase-secret-key
PORT=3000

The code still uses the legacy name SUPABASE_SERVICE_ROLE_KEY; put your secret key there without renaming anything. It has to be the secret key or the legacy service_role key, not the publishable key, which is meant for browser code and does not have the access the server needs. PORT is optional: without it, the server uses 3000.

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.

Keep the Supabase key on the server

Your Supabase secret key can read and change everything in your database. In this project only the server reads it, and that is the only safe place for it: never copy it into client.js, and never commit or share .env.

JunoAdd your keys to .env Make a file called .env next to package.json with your values on the first three lines, then list .env in .gitignore so Git never saves it.
JunoAdd your keys to .env Node reads .env once, when the server starts. After any change to it, stop the server with Ctrl+C and start it again.
JunoAdd your keys to .env The browser only ever talks to your own server: client.js posts the question to /api/ask and gets back an answer and its sources. No key is in anything the browser downloads.

Start the agent and ask a question ​

Start the server:

bash
$ npm start

> start
> node --env-file=.env server.js

Server listening at http://localhost:3000

Open http://localhost:3000, or the port you set in .env. The Support AI Chatbot page has a box for your question and an Ask button. Ask a question about Scrimba, such as how to reset your password. The page shows Thinking… while the agent works, then the answer. When the answer comes from your Supabase documents, View Sources under it lists the passages it used, each with a similarity score: OpenAI and Supabase both work. A general question, about the news for example, is answered with web search and lists web pages instead; that one needs only OpenAI. The RAG chapter explains why the agent looks things up before it answers.

If the answer reads I encountered an error while processing your request using tool calling. Please try again later., the page can't tell you why. The reason is in the terminal where the server runs, under the line [ToolBased] Error in RAG process:.

Stop the server with Ctrl+C.

JunoStart the agent and ask a question Run npm start, wait for Server listening at http://localhost:3000, and open that address. Ask a question about Scrimba and wait for the answer.

If the answer says it encountered an error, read the terminal, not the page.

JunoStart the agent and ask a question The page opening only shows that Express serves files. For each question, the model first chooses a tool: the knowledge base, which needs Supabase, or web search. View Sources tells you which one it chose.
JunoStart the agent and ask a questionwebSearchRetrievalAgent catches every error during the question and returns that fixed apology with status 200, so the page never sees the cause. A Supabase error goes to the model as the tool's result instead, so you get an answer with no sources and a [Tool:KB] line in the terminal.

Troubleshooting ​

The server stops at once with Missing OPENAI_API_KEY environment variable: Node didn't load .env. Check that the start script says node --env-file=.env server.js and that the name in .env is exactly OPENAI_API_KEY. SUPABASE_SERVICE_ROLE_KEY is missing or invalid and SUPABASE_URL is missing or invalid mean the same for those names.

node: .env: not found: The start script is right, but there is no .env beside package.json. Check that the file is named exactly .env, not .env.txt.

Invalid supabaseUrl: Must be a valid HTTP or HTTPS URL.: SUPABASE_URL has to be the full address from the Connect dialog, starting with https://.

Error: listen EADDRINUSE: address already in use :::3000: Another program is using port 3000, often an earlier run of this server in another terminal. Stop it with Ctrl+C, or set PORT=3001 in .env, start again and open http://localhost:3001.

The answer says it encountered an error, and the terminal says Incorrect API key provided: OpenAI rejected the key with a 401. Copy it again from your OpenAI account, check that it has not been deleted, then restart the server.

The terminal says You exceeded your current quota: The key works, but the OpenAI account has no credit to spend. Add billing in your OpenAI account, then ask again.

A Scrimba question gets an answer with no sources, and the terminal shows a line starting [Tool:KB] Error: OpenAI works, but Supabase didn't return the course documents. Check that the URL and the secret key come from the same project, that the key is the secret or service_role key rather than the publishable one, and that the project still has the course's documents and its match_documents function.

The terminal says the model gpt-4o is not available: OpenAI shuts gpt-4o down on January 14, 2027, and names gpt-6-luna as its replacement. Change ANSWERING_MODEL in constants.js to the replacement on OpenAI's deprecations page. Leave EMBEDDING_MODEL_NAME as text-embedding-3-small: the documents in Supabase were embedded with it, and a different embedding model finds poor matches without any error.

JunoTroubleshooting Notice where the error shows. If the server stops right after npm start, the problem is in package.json or .env. If the page answers with an apology, the reason is in the server's terminal.
JunoTroubleshooting The failures come in order: Node loading .env, the Supabase URL check, the port, then OpenAI on each question, then Supabase inside the knowledge-base tool. Fix the first one you meet.
JunoTroubleshooting Startup errors come from config.js, which checks each variable and builds both clients as soon as server.js loads it, so they stop the process. Errors during a question are caught and logged, so the server keeps running while you fix .env; restart it to load the change.