Awesome Free LLM APIs IR

Using a Free LLM API in Node.js with a Custom Base URL

Practical tutorial for connecting Node.js to OpenAI-compatible free LLM APIs, managing environment variables, streaming, timeout, retry, errors, and building a secure chat endpoint.

Last reviewed: 2026-07-18

In this tutorial, you will build a swappable Node.js client for OpenAI-compatible free LLM providers. The API key is not stored in the source code, settings are read from environment variables, and key errors (401, 404, 429, timeout, and transient service failures) are handled separately.

Use the Free LLM API Catalog to choose a provider, Base URL, and Model ID. Quotas, models, and access conditions can change — always check the provider page and official documentation before running.

Prerequisites

  • Node.js 18 or later
  • npm or yarn
  • API key from an OpenAI-compatible provider
  • Correct Base URL and Model ID
  • Understanding of the free-tier type and Iran-access status

Step 1: Set up the project

mkdir free-llm-nodejs
cd free-llm-nodejs
npm init -y
npm install openai dotenv

Project structure:

free-llm-nodejs/
├── index.js
├── .env
├── .env.example
└── .gitignore

Step 2: Configure environment variables

.env:

LLM_API_KEY=replace_me
LLM_BASE_URL=https://provider.example/v1
LLM_MODEL=MODEL_ID

.env.example:

LLM_API_KEY=
LLM_BASE_URL=
LLM_MODEL=

.gitignore:

.env
.env.*
!.env.example
node_modules/

Step 3: Build the client

index.js:

import "dotenv/config";
import OpenAI from "openai";

const required = ["LLM_API_KEY", "LLM_BASE_URL", "LLM_MODEL"];
const missing = required.filter((key) => !process.env[key]);
if (missing.length) {
  throw new Error(`Missing environment variables: ${missing.join(", ")}`);
}

const client = new OpenAI({
  apiKey: process.env.LLM_API_KEY,
  baseURL: process.env.LLM_BASE_URL,
  timeout: 30000,
  maxRetries: 2,
});

const messages = [
  {
    role: "system",
    content:
      "You are a precise Persian assistant. Answer clearly and concisely.",
  },
];

async function chat() {
  const rl = (await import("readline")).createInterface({
    input: process.stdin,
    output: process.stdout,
  });

  console.log('Chatbot ready. Type "exit" to quit.');

  const ask = () => {
    rl.question("You: ", async (input) => {
      if (!input.trim()) return ask();
      if (input.toLowerCase() === "exit") return rl.close();

      messages.push({ role: "user", content: input });

      try {
        const response = await client.chat.completions.create({
          model: process.env.LLM_MODEL,
          messages: messages.slice(-12),
          temperature: 0.3,
        });

        const answer =
          response.choices[0]?.message?.content || "No response received.";
        console.log("Assistant:", answer);
        messages.push({ role: "assistant", content: answer });
      } catch (err) {
        if (err.status === 401) {
          console.log("Error: Invalid API key or account permissions.");
        } else if (err.status === 429) {
          console.log(
            "Error: Rate limit or quota exceeded. Try again later."
          );
        } else if (err.code === "ECONNREFUSED" || err.code === "ENOTFOUND") {
          console.log("Error: Check network and LLM_BASE_URL.");
        } else {
          console.log(`Error: ${err.message}`);
        }
      }

      ask();
    });
  };

  ask();
}

chat();

Step 4: Run the application

node index.js

Adding streaming

const stream = await client.chat.completions.create({
  model: process.env.LLM_MODEL,
  messages: messages.slice(-12),
  stream: true,
});

process.stdout.write("Assistant: ");
for await (const event of stream) {
  const text = event.choices[0]?.delta?.content || "";
  process.stdout.write(text);
}
process.stdout.write("\n");

Verify streaming support with your provider before using.

Error management

Error patternLikely causeAction
401Invalid/expired keyCheck key and account
404Wrong URL or modelCheck Base URL and Model ID
429Rate limit or quotaRetry with backoff
ECONNREFUSEDNetwork or URLVerify endpoint
TimeoutSlow inferenceIncrease timeout
5xxServer errorRetry with backoff

Never log the API key or print it in error messages.

Environment variable switching

To switch providers, update only .env:

LLM_API_KEY=new_key
LLM_BASE_URL=https://new-provider.example/v1
LLM_MODEL=new-model-id

Test tool calling, streaming, and parameter differences before fully switching.

Production checklist

  • API key in a secret manager, not in .env.
  • Input validation and length limits.
  • Rate limiting at the application level.
  • Structured logging without secrets.
  • Circuit breaker for provider failures.
  • Graceful degradation with fallback provider.

Summary

With the OpenAI Node.js SDK and environment-based configuration, you can build a maintainable, swappable LLM client. Focus on error handling, secret management, and provider independence — not just sending requests.

Find current provider options in the live catalog. Submit sanitized Iran-access results through the Iran Access Report form.