DeepSeek Node.js TypeScript Guide: Chat Completions, Streaming, JSON & Tools

Last verified: April 27, 2026.

To use DeepSeek Node.js TypeScript in a production-ready way, install the OpenAI JavaScript/TypeScript SDK, configure it with DeepSeek’s OpenAI-compatible base URL, store your API key on the server, and call the current V4 model IDs: deepseek-v4-flash or deepseek-v4-pro.

Independent site disclosure: Chat-Deep.ai is an independent DeepSeek guide and browser access site. It is not the official DeepSeek website, not the official DeepSeek app, not the official DeepSeek developer platform, and not affiliated with DeepSeek. For the broad overview, start with our DeepSeek AI guide. This article focuses only on the developer intent: using DeepSeek with Node.js and TypeScript.

Table of Contents

  1. Quick Answer
  2. What “DeepSeek Node.js SDK” Means
  3. Install the SDK
  4. Set Your API Key Safely
  5. Minimal TypeScript Example
  6. Choose deepseek-v4-flash or deepseek-v4-pro
  7. Next.js API Route Example
  8. Streaming Responses
  9. Multi-turn Chat
  10. JSON Output
  11. Tool Calls
  12. Thinking Mode
  13. Error Handling
  14. Token Usage and Context Caching
  15. Legacy Migration
  16. FAQ

Quick Answer: DeepSeek with Node.js and TypeScript

The practical route for DeepSeek Node.js TypeScript projects is to use the OpenAI JavaScript/TypeScript SDK, point it to DeepSeek’s API endpoint, and keep your DeepSeek API key on the server.

  1. Install the SDK with npm install openai.
  2. Store your key in DEEPSEEK_API_KEY.
  3. Create an SDK client with baseURL: "https://api.deepseek.com".
  4. Use deepseek-v4-flash for fast everyday chat, summaries, extraction, JSON Output, classification, and routine coding help.
  5. Use deepseek-v4-pro for harder reasoning, complex coding, long-context analysis, tool planning, and higher-value production workflows.
  6. Never expose DEEPSEEK_API_KEY in browser JavaScript.

For a broader API overview, read our DeepSeek API guide. For cross-SDK setup notes, see OpenAI SDK with DeepSeek.

What “DeepSeek Node.js SDK” Means

In this guide, DeepSeek Node.js SDK means the OpenAI JavaScript/TypeScript SDK configured for DeepSeek. DeepSeek’s official quick-start path for Node.js uses the openai package, a DeepSeek API key, and DeepSeek’s OpenAI-compatible base URL.

Do not assume that every package called a DeepSeek SDK is official. Before using a third-party package, review its source code, maintenance history, dependency chain, security posture, and documentation. For most Node.js and TypeScript projects, the documented and simplest path is the OpenAI SDK configured for DeepSeek.

Important TypeScript detail: use baseURL and apiKey in Node.js. Do not use Python-style names such as base_url or api_key in TypeScript code.

Install the OpenAI SDK for a DeepSeek TypeScript Project

Start with a normal Node.js and TypeScript project. Install the runtime packages:

npm install openai dotenv

Then install TypeScript development dependencies:

npm install -D typescript tsx @types/node

A simple development script can look like this:

{
  "scripts": {
    "dev": "tsx src/index.ts"
  }
}

A clean starter structure:

your-project/
  src/
    index.ts
  .env
  .gitignore
  package.json
  tsconfig.json

If you are building with Next.js, Express, Fastify, serverless functions, or another backend framework, keep the DeepSeek call server-side. Browser code should call your own backend route, and your backend should call DeepSeek.

Set Your DeepSeek API Key Safely

Create a .env file:

DEEPSEEK_API_KEY=your_deepseek_api_key_here

Add environment files to .gitignore:

.env
.env.local
.env.*.local

Do not put DEEPSEEK_API_KEY in browser JavaScript, static HTML, frontend configuration, GitHub commits, public Next.js variables, logs, analytics events, or client-visible error messages.

For a browser chat UI, create a backend API route. The browser sends the user’s message to your server, and your server calls DeepSeek with the private key.

Minimal DeepSeek TypeScript Example

This example uses deepseek-v4-flash for a fast non-thinking chat request. It also uses a narrow local type extension because SDK typings may not always include DeepSeek-specific fields such as thinking.

// src/index.ts
import "dotenv/config";
import OpenAI from "openai";

function getEnv(name: string): string {
  const value = process.env[name];

  if (!value) {
    throw new Error(`Missing required environment variable: ${name}`);
  }

  return value;
}

const client = new OpenAI({
  apiKey: getEnv("DEEPSEEK_API_KEY"),
  baseURL: "https://api.deepseek.com",
});

type DeepSeekThinkingOptions = {
  thinking?: {
    type: "enabled" | "disabled";
  };
  reasoning_effort?: "high" | "max";
};

type DeepSeekChatRequest =
  Parameters<typeof client.chat.completions.create>[0] &
  DeepSeekThinkingOptions;

async function main() {
  const request: DeepSeekChatRequest = {
    model: "deepseek-v4-flash",
    messages: [
      {
        role: "system",
        content:
          "You are a concise TypeScript assistant. Answer clearly and safely.",
      },
      {
        role: "user",
        content: "Show me a TypeScript function that validates an email string.",
      },
    ],
    thinking: { type: "disabled" },
    stream: false,
  };

  const completion = await client.chat.completions.create(request);
  const text = completion.choices[0]?.message?.content;

  if (!text) {
    throw new Error("The model returned an empty response.");
  }

  console.log(text);
}

main().catch((error) => {
  console.error("DeepSeek request failed:");
  console.error(error);
  process.exit(1);
});

Choosing deepseek-v4-flash vs deepseek-v4-pro

For new code, use the current official model IDs: deepseek-v4-flash and deepseek-v4-pro. Do not use legacy names as the primary examples in new developer documentation.

Model IDBest forTypical Node.js / TypeScript use cases
deepseek-v4-flashFast everyday workChatbots, summaries, extraction, JSON Output, classification, routine coding help, support drafts, product descriptions
deepseek-v4-proHarder reasoning and higher-value workflowsComplex coding, long-context analysis, agentic workflows, difficult debugging, tool planning, research synthesis

For current API rates, check the official DeepSeek Models & Pricing page before production use. You can also read the independent DeepSeek API pricing guide on Chat-Deep.ai for plain-English context. This article does not include fixed prices because pricing can change.

For model-level context, read our DeepSeek models guide.

Next.js API Route Example

In a Next.js App Router project, create app/api/deepseek/route.ts. This keeps your DeepSeek API key server-side and gives the browser a safe route to call.

// app/api/deepseek/route.ts
import OpenAI from "openai";
import { NextRequest, NextResponse } from "next/server";

export const runtime = "nodejs";

function getEnv(name: string): string {
  const value = process.env[name];

  if (!value) {
    throw new Error(`Missing required environment variable: ${name}`);
  }

  return value;
}

const client = new OpenAI({
  apiKey: getEnv("DEEPSEEK_API_KEY"),
  baseURL: "https://api.deepseek.com",
});

type DeepSeekThinkingOptions = {
  thinking?: {
    type: "enabled" | "disabled";
  };
  reasoning_effort?: "high" | "max";
};

type DeepSeekChatRequest =
  Parameters<typeof client.chat.completions.create>[0] &
  DeepSeekThinkingOptions;

function isValidBody(value: unknown): value is { message: string } {
  if (!value || typeof value !== "object") return false;

  const candidate = value as { message?: unknown };

  return (
    typeof candidate.message === "string" &&
    candidate.message.trim().length > 0 &&
    candidate.message.length <= 4000
  );
}

export async function POST(req: NextRequest) {
  let body: unknown;

  try {
    body = await req.json();
  } catch {
    return NextResponse.json(
      { error: "Invalid JSON request body." },
      { status: 400 }
    );
  }

  if (!isValidBody(body)) {
    return NextResponse.json(
      { error: "Expected a non-empty message string up to 4000 characters." },
      { status: 400 }
    );
  }

  try {
    const request: DeepSeekChatRequest = {
      model: "deepseek-v4-flash",
      messages: [
        {
          role: "system",
          content:
            "You are a helpful assistant. Give practical, concise answers.",
        },
        {
          role: "user",
          content: body.message,
        },
      ],
      thinking: { type: "disabled" },
      max_tokens: 700,
      stream: false,
    };

    const completion = await client.chat.completions.create(request);
    const answer = completion.choices[0]?.message?.content ?? "";

    return NextResponse.json({
      answer,
      model: "deepseek-v4-flash",
      usage: completion.usage ?? null,
    });
  } catch (error) {
    console.error("DeepSeek API error:", error);

    return NextResponse.json(
      { error: "The DeepSeek request failed." },
      { status: 500 }
    );
  }
}

For production, add authentication, abuse protection, rate limiting, input limits, request logging rules, and a privacy policy for sensitive user data. Do not log API keys, private prompts, or confidential responses unless your security review explicitly permits it.

Streaming DeepSeek Responses in TypeScript

Streaming is useful for chat UIs because the user can see partial output as it arrives. Set stream: true and iterate over chunks with for await...of.

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

const client = new OpenAI({
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseURL: "https://api.deepseek.com",
});

type DeepSeekThinkingOptions = {
  thinking?: {
    type: "enabled" | "disabled";
  };
  reasoning_effort?: "high" | "max";
};

type DeepSeekChatRequest =
  Parameters<typeof client.chat.completions.create>[0] &
  DeepSeekThinkingOptions;

async function streamAnswer() {
  const request: DeepSeekChatRequest = {
    model: "deepseek-v4-flash",
    messages: [
      {
        role: "user",
        content: "Explain server-side API key handling in a Node.js app.",
      },
    ],
    thinking: { type: "disabled" },
    stream: true,
    stream_options: {
      include_usage: true,
    },
  };

  const stream = await client.chat.completions.create(request);

  for await (const chunk of stream) {
    const delta = chunk.choices[0]?.delta;

    if (delta?.content) {
      process.stdout.write(delta.content);
    }

    if (chunk.usage) {
      console.log("\n\nUsage:", chunk.usage);
    }
  }
}

streamAnswer().catch((error) => {
  console.error(error);
  process.exit(1);
});

In thinking mode, reasoning-related fields may appear separately from final answer content. Most user interfaces should show the final answer content by default, not raw reasoning fields.

Multi-turn Chat in TypeScript

The DeepSeek Chat Completions API is stateless. Your application must store conversation history and send the relevant history with each request. For ordinary chat, store the final assistant content that the user saw.

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

const client = new OpenAI({
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseURL: "https://api.deepseek.com",
});

type Message = {
  role: "system" | "user" | "assistant";
  content: string;
};

type DeepSeekThinkingOptions = {
  thinking?: {
    type: "enabled" | "disabled";
  };
};

type DeepSeekChatRequest =
  Parameters<typeof client.chat.completions.create>[0] &
  DeepSeekThinkingOptions;

async function main() {
  const messages: Message[] = [
    {
      role: "system",
      content: "You are a helpful TypeScript mentor.",
    },
    {
      role: "user",
      content: "What is a discriminated union in TypeScript?",
    },
  ];

  const firstRequest: DeepSeekChatRequest = {
    model: "deepseek-v4-flash",
    messages,
    thinking: { type: "disabled" },
  };

  const first = await client.chat.completions.create(firstRequest);
  const firstAnswer = first.choices[0]?.message?.content ?? "";

  messages.push({
    role: "assistant",
    content: firstAnswer,
  });

  messages.push({
    role: "user",
    content: "Show me a small example.",
  });

  const secondRequest: DeepSeekChatRequest = {
    model: "deepseek-v4-flash",
    messages,
    thinking: { type: "disabled" },
  };

  const second = await client.chat.completions.create(secondRequest);
  console.log(second.choices[0]?.message?.content ?? "");
}

main().catch(console.error);

Thinking-mode tool-call loops are different. During an active thinking and tool-call loop, preserve the full assistant message when it includes reasoning_content and tool_calls.

DeepSeek JSON Output TypeScript

Use JSON Output when your app needs structured data for extraction, classification, routing, tagging, form filling, or workflow decisions.

The key rules are:

  • Set response_format: { type: "json_object" }.
  • Explicitly include the word json in the system or user prompt.
  • Provide the desired JSON shape.
  • Set max_tokens reasonably.
  • Parse and validate the response before using it.
import "dotenv/config";
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseURL: "https://api.deepseek.com",
});

type DeepSeekThinkingOptions = {
  thinking?: {
    type: "enabled" | "disabled";
  };
};

type DeepSeekChatRequest =
  Parameters<typeof client.chat.completions.create>[0] &
  DeepSeekThinkingOptions;

type TicketLabel = {
  category: "billing" | "technical" | "account" | "other";
  priority: "low" | "medium" | "high";
  summary: string;
};

function isTicketLabel(value: unknown): value is TicketLabel {
  if (!value || typeof value !== "object") return false;

  const candidate = value as Record<string, unknown>;

  return (
    ["billing", "technical", "account", "other"].includes(
      String(candidate.category)
    ) &&
    ["low", "medium", "high"].includes(String(candidate.priority)) &&
    typeof candidate.summary === "string" &&
    candidate.summary.length > 0
  );
}

async function classifyTicket(input: string): Promise<TicketLabel> {
  const request: DeepSeekChatRequest = {
    model: "deepseek-v4-flash",
    messages: [
      {
        role: "system",
        content: `
Return only valid json.

Classify the support ticket into this JSON shape:
{
  "category": "billing | technical | account | other",
  "priority": "low | medium | high",
  "summary": "short summary"
}
        `.trim(),
      },
      {
        role: "user",
        content: input,
      },
    ],
    response_format: { type: "json_object" },
    thinking: { type: "disabled" },
    max_tokens: 400,
  };

  const completion = await client.chat.completions.create(request);
  const content = completion.choices[0]?.message?.content;

  if (!content) {
    throw new Error("Empty JSON Output response.");
  }

  const parsed: unknown = JSON.parse(content);

  if (!isTicketLabel(parsed)) {
    throw new Error("JSON Output did not match the expected schema.");
  }

  return parsed;
}

classifyTicket("I cannot log in after resetting my password.")
  .then(console.log)
  .catch(console.error);

Valid JSON is not the same as trusted business data. Always validate types, ranges, enums, permissions, and workflow-specific rules before taking action.

For a deeper explanation, read DeepSeek JSON Output.

DeepSeek Tool Calls TypeScript

Tool Calls let the model request a structured function call. The model does not execute your function. Your application must validate arguments, execute the function, append a tool message with the matching tool_call_id, and send another request for the final answer.

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

const client = new OpenAI({
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseURL: "https://api.deepseek.com",
});

type DeepSeekThinkingOptions = {
  thinking?: {
    type: "enabled" | "disabled";
  };
};

type DeepSeekChatRequest =
  Parameters<typeof client.chat.completions.create>[0] &
  DeepSeekThinkingOptions;

type OrderStatusArgs = {
  orderId: string;
};

function parseOrderStatusArgs(raw: string): OrderStatusArgs {
  const parsed: unknown = JSON.parse(raw);

  if (!parsed || typeof parsed !== "object") {
    throw new Error("Tool arguments must be an object.");
  }

  const value = parsed as Record<string, unknown>;

  if (typeof value.orderId !== "string") {
    throw new Error("Missing orderId.");
  }

  if (!/^ORD-[A-Z0-9]{6,20}$/.test(value.orderId)) {
    throw new Error("Invalid orderId format.");
  }

  return {
    orderId: value.orderId,
  };
}

function getOrderStatus(args: OrderStatusArgs) {
  return {
    orderId: args.orderId,
    status: "processing",
    message: "The order is being prepared for shipment.",
  };
}

async function main() {
  const tools = [
    {
      type: "function",
      function: {
        name: "get_order_status",
        description: "Look up the current status of a customer order.",
        parameters: {
          type: "object",
          properties: {
            orderId: {
              type: "string",
              description: "Order ID, for example ORD-ABC123",
            },
          },
          required: ["orderId"],
        },
      },
    },
  ];

  const messages: Array<Record<string, unknown>> = [
    {
      role: "system",
      content:
        "You are a support assistant. Use tools when order status is needed.",
    },
    {
      role: "user",
      content: "Can you check order ORD-ABC123?",
    },
  ];

  const firstRequest: DeepSeekChatRequest = {
    model: "deepseek-v4-flash",
    messages: messages as never,
    tools: tools as never,
    tool_choice: "auto",
    thinking: { type: "disabled" },
  };

  const first = await client.chat.completions.create(firstRequest);
  const assistantMessage = first.choices[0]?.message;

  if (!assistantMessage) {
    throw new Error("Missing assistant message.");
  }

  messages.push(assistantMessage as unknown as Record<string, unknown>);

  const toolCall = assistantMessage.tool_calls?.[0];

  if (!toolCall) {
    console.log(assistantMessage.content ?? "");
    return;
  }

  if (toolCall.function.name !== "get_order_status") {
    throw new Error(`Unsupported tool: ${toolCall.function.name}`);
  }

  const args = parseOrderStatusArgs(toolCall.function.arguments);
  const result = getOrderStatus(args);

  messages.push({
    role: "tool",
    tool_call_id: toolCall.id,
    content: JSON.stringify(result),
  });

  const finalRequest: DeepSeekChatRequest = {
    model: "deepseek-v4-flash",
    messages: messages as never,
    thinking: { type: "disabled" },
  };

  const final = await client.chat.completions.create(finalRequest);
  console.log(final.choices[0]?.message?.content ?? "");
}

main().catch(console.error);

Validate tool arguments before executing anything. This matters for database queries, account changes, file operations, external API calls, order workflows, and automation.

For more implementation detail, read DeepSeek Tool Calls.

Thinking Mode in Node.js

Thinking mode is useful for harder reasoning, complex coding, difficult debugging, long-context analysis, and multi-step planning. For routine tasks, non-thinking mode is often enough.

Use deepseek-v4-pro with thinking: { type: "enabled" } and reasoning_effort: "high" for harder tasks.

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

const client = new OpenAI({
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseURL: "https://api.deepseek.com",
});

type DeepSeekThinkingOptions = {
  thinking?: {
    type: "enabled" | "disabled";
  };
  reasoning_effort?: "high" | "max";
};

type DeepSeekChatRequest =
  Parameters<typeof client.chat.completions.create>[0] &
  DeepSeekThinkingOptions;

type DeepSeekMessage = {
  content?: string | null;
  reasoning_content?: string | null;
};

async function main() {
  const request: DeepSeekChatRequest = {
    model: "deepseek-v4-pro",
    messages: [
      {
        role: "user",
        content:
          "Design a TypeScript architecture for a multi-tenant support chatbot with tool calls.",
      },
    ],
    thinking: { type: "enabled" },
    reasoning_effort: "high",
    stream: false,
  };

  const completion = await client.chat.completions.create(request);
  const message = completion.choices[0]?.message as DeepSeekMessage | undefined;

  if (!message?.content) {
    throw new Error("Missing final answer content.");
  }

  console.log(message.content);
}

main().catch(console.error);

The final user-facing answer is returned as content. Thinking-related output may be returned separately as reasoning_content. UI builders should usually show final content, not raw reasoning fields.

When thinking mode and Tool Calls are used together, preserve the full assistant message during the active loop if it includes reasoning_content and tool_calls. This helps the model continue the same reasoning-and-tool sequence correctly.

For a dedicated explanation, read DeepSeek Thinking Mode.

Strict Tool Schemas and Beta Features

Strict Tool Calls are a beta feature. If you use strict mode, use the beta base URL required by the official documentation and set strict: true in the function definition.

Keep strict schemas narrow. Prefer required fields, clear enums, and additionalProperties: false where appropriate. Keep beta features isolated in your codebase, test them separately, and verify behavior before production rollout.

Error Handling, Retries, and Timeouts

A production DeepSeek API Node.js integration should handle request errors explicitly instead of exposing raw API errors to users.

StatusMeaningPractical handling
400Invalid request body formatFix messages, parameters, tool messages, or request shape.
401Authentication failsCheck the DeepSeek API key and server environment variable.
402Account balance issueCheck the official DeepSeek platform account.
422Invalid parametersRemove unsupported or malformed parameters.
429Rate limit reachedQueue work, reduce concurrency, and retry with backoff.
500Server errorRetry after a brief delay and degrade gracefully.
503Server overloadedRetry later and show a safe fallback message.
import OpenAI from "openai";

async function runSafely(fn: () => Promise<void>) {
  try {
    await fn();
  } catch (error) {
    if (error instanceof OpenAI.APIError) {
      switch (error.status) {
        case 400:
          console.error("Invalid request format:", error.message);
          return;
        case 401:
          console.error("Authentication failed. Check DEEPSEEK_API_KEY.");
          return;
        case 402:
          console.error("Account balance or billing issue.");
          return;
        case 422:
          console.error("Invalid parameters:", error.message);
          return;
        case 429:
          console.error("Rate limit reached. Retry with backoff.");
          return;
        case 500:
        case 503:
          console.error("DeepSeek service issue. Retry after a brief wait.");
          return;
        default:
          console.error("API error:", error.status, error.message);
          return;
      }
    }

    throw error;
  }
}

For high-volume systems, add request timeouts, retry limits, exponential backoff, queueing, concurrency limits, and incident checks.

Token Usage and Context Caching

Read token usage from the API response instead of guessing from character count. Usage fields help you observe prompt size, completion size, total tokens, and cache behavior.

type DeepSeekUsage = {
  prompt_tokens?: number;
  completion_tokens?: number;
  total_tokens?: number;
  prompt_cache_hit_tokens?: number;
  prompt_cache_miss_tokens?: number;
  completion_tokens_details?: {
    reasoning_tokens?: number;
  };
};

function logUsage(usage: unknown) {
  const value = usage as DeepSeekUsage | undefined;

  if (!value) return;

  console.log("prompt_tokens:", value.prompt_tokens);
  console.log("completion_tokens:", value.completion_tokens);
  console.log("total_tokens:", value.total_tokens);
  console.log("prompt_cache_hit_tokens:", value.prompt_cache_hit_tokens);
  console.log("prompt_cache_miss_tokens:", value.prompt_cache_miss_tokens);
  console.log(
    "reasoning_tokens:",
    value.completion_tokens_details?.reasoning_tokens
  );
}

DeepSeek context caching is enabled by default. In production, monitor prompt_cache_hit_tokens and prompt_cache_miss_tokens where available so you can understand how repeated prefixes, system prompts, prompt templates, and long contexts behave.

Do not hard-code pricing assumptions. For current API rates, check the official DeepSeek Models & Pricing page before production use. For an independent explanation, see the DeepSeek API pricing guide.

For more detail, read DeepSeek Context Caching.

Legacy Migration: deepseek-chat and deepseek-reasoner

For new Node.js and TypeScript examples, do not use deepseek-chat or deepseek-reasoner as primary model names.

They are legacy compatibility aliases. During the transition, deepseek-chat maps to deepseek-v4-flash non-thinking behavior, and deepseek-reasoner maps to deepseek-v4-flash thinking behavior. They are scheduled for retirement after July 24, 2026, 15:59 UTC.

Recommended migration

// Old:
model: "deepseek-chat"

// New:
model: "deepseek-v4-flash",
thinking: { type: "disabled" }
// Old:
model: "deepseek-reasoner"

// New:
model: "deepseek-v4-pro",
thinking: { type: "enabled" },
reasoning_effort: "high"

Update older code before the retirement date to avoid broken integrations.

Common DeepSeek API Node.js Mistakes

  • Using base_url instead of baseURL in TypeScript.
  • Using api_key instead of apiKey in Node.js.
  • Using legacy model aliases in new integrations
  • Exposing API keys in browser code.
  • Using an OpenAI API key with DeepSeek’s base URL.
  • Using a DeepSeek API key with the default OpenAI endpoint.
  • Treating /v1 as a model version.
  • Copying Responses API examples instead of Chat Completions examples.
  • Forgetting to validate JSON Output.
  • Executing tool calls without validating arguments.
  • Assuming pricing never changes.
  • Ignoring finish_reason.
  • Logging unnecessary sensitive prompts or responses.

Production Checklist

  • API key is server-side only.
  • Environment variables are configured safely.
  • DEEPSEEK_API_KEY is not committed to Git.
  • Code uses current model IDs.
  • baseURL is set to https://api.deepseek.com.
  • Request bodies are validated.
  • User input length is limited.
  • Output is validated before automation.
  • Tool arguments are parsed and validated.
  • Timeouts are configured.
  • Retries use backoff and limits.
  • Concurrency is controlled.
  • Token usage is monitored.
  • Context caching fields are reviewed when relevant.
  • No static pricing assumptions are hard-coded.
  • Official DeepSeek documentation is checked before launch.

For a simpler starting point, read create a DeepSeek chat completion.

FAQ

How do I use DeepSeek with Node.js and TypeScript?

Install the OpenAI JavaScript/TypeScript SDK, create an OpenAI client with baseURL: "https://api.deepseek.com", store your DeepSeek API key in DEEPSEEK_API_KEY, and call client.chat.completions.create() with deepseek-v4-flash or deepseek-v4-pro.

Does DeepSeek have an official Node.js SDK?

DeepSeek’s official quick start documents Node.js usage through the OpenAI JavaScript/TypeScript SDK configured with DeepSeek’s base URL. In this guide, “DeepSeek Node.js SDK” means that documented SDK setup.

What baseURL should I use for DeepSeek in Node.js?

Use baseURL: "https://api.deepseek.com" for normal OpenAI-compatible DeepSeek API requests in Node.js and TypeScript.

Which model should I use, deepseek-v4-flash or deepseek-v4-pro?

Use deepseek-v4-flash for fast everyday chat, extraction, summaries, JSON Output, classification, and routine coding help. Use deepseek-v4-pro for harder reasoning, complex coding, long-context analysis, tool planning, and higher-value production workflows.

Should I still use deepseek-chat or deepseek-reasoner?

No, not for new examples. They are legacy compatibility aliases. Use deepseek-v4-flash or deepseek-v4-pro in new code, and migrate old examples before the scheduled retirement date.

Can I stream DeepSeek responses in TypeScript?

Yes. Set stream: true in client.chat.completions.create() and iterate with for await...of. Read delta.content for normal streamed output.

How do I return JSON from DeepSeek in TypeScript?

Set response_format: { type: "json_object" }, explicitly ask for json in the prompt, provide a target JSON shape, set max_tokens, parse the result, and validate the parsed object.

How do Tool Calls work with DeepSeek?

The model can request a function call, but it does not execute your function. Your application validates the arguments, runs the function, appends a tool message with the matching tool_call_id, and sends another request for the final answer.

Can I call DeepSeek directly from browser JavaScript?

Do not call DeepSeek directly from browser JavaScript with a secret API key. Use a server-side route, backend API, or serverless function so the key remains private.

Where can I check current DeepSeek API pricing?

For current API rates, check the official DeepSeek Models & Pricing page before production use. Do not rely on old copied pricing tables.

Official Sources and Last Verified

Last verified: April 27, 2026.

DeepSeek model names, endpoint behavior, beta features, output limits, and pricing can change. Use official DeepSeek documentation before shipping production code.

Related Chat-Deep.ai guides: DeepSeek AI guide, DeepSeek API guide, OpenAI SDK with DeepSeek, DeepSeek models, DeepSeek JSON Output, DeepSeek Tool Calls, DeepSeek Thinking Mode, DeepSeek Context Caching, and DeepSeek API pricing guide.