LangSync

SDK

Drive LangSync workflows in-process from Node.js with the @mariokreitz/langsync-sdk package.

The LangSync SDK (@mariokreitz/langsync-sdk) exposes LangSync's command runners as in-process functions. Editor integrations, custom scripts, build plugins, and CI tooling can run the exact workflows the CLI uses without spawning a child process.

Every runner takes an explicit cwd, returns a structured result object, and never logs, prompts, or calls process.exit. This makes the SDK safe to embed in long-running hosts such as a VS Code extension or a dev server.

Why a dedicated package

The SDK ships independently from the langsync CLI so you can depend on the programmatic surface without pulling in command-line dependencies. It is the same engine that powers the CLI and the official VS Code extension, exposed through a stable, semver-versioned API.

The CLI re-exports the SDK for backward compatibility, but new integrations should depend on @mariokreitz/langsync-sdk directly.

Installation

npm install @mariokreitz/langsync-sdk
pnpm add @mariokreitz/langsync-sdk
yarn add @mariokreitz/langsync-sdk

Import

import {
  defineConfig,
  loadConfig,
  runValidate,
  runSync,
  runFindMissing,
  runTranslate,
} from '@mariokreitz/langsync-sdk';

Loading config

loadConfig resolves the LangSync config from an explicit working directory and returns null when no config is found.

const loaded = await loadConfig(process.cwd());
 
if (!loaded) {
  throw new Error('No LangSync config found. Run `langsync init` first.');
}

Validate

const result = await runValidate({ cwd: process.cwd() });
 
// result.referenceLocale  -> string
// result.issues           -> NamespacedValidationIssue[]
// result.exitCode         -> 0 | 1  (1 when missing/extra issues exist)
 
for (const issue of result.issues) {
  console.log(`${issue.type} ${issue.locale} ${issue.key} (${issue.path})`);
}

Sync

// Add missing keys to non-reference locales as empty placeholders.
const result = await runSync({ cwd: process.cwd() });
 
// result.written       -> string[]  (paths written; empty in dry-run)
// result.planned       -> string[]  (paths that would change)
// result.unchanged     -> string[]
// result.diffsByPath   -> Record<string, TreeDiff>
 
// Preview without writing:
const preview = await runSync({ cwd: process.cwd(), dryRun: true });

Find missing

const result = await runFindMissing({ cwd: process.cwd() });
 
// result.missingByLocale -> Record<string, MissingEntry[]>
// result.exitCode        -> 0 | 1

Translate

const result = await runTranslate({
  cwd: process.cwd(),
  maxKeys: 50, // cap total keys translated across all locales
  dryRun: true, // preview candidates without calling the provider
  // provider: 'openai', // override the configured provider
  // model: 'gpt-5-mini', // override the configured model
});
 
// result.translatedByLocale -> Record<string, TranslationEntry[]>
// result.skippedByLocale    -> Record<string, TranslationEntry[]>

Defining config in TypeScript

defineConfig gives you a fully typed langsync.config.ts and is re-exported by both the SDK and the CLI:

import { defineConfig } from '@mariokreitz/langsync-sdk';
 
export default defineConfig({
  input: './src/locales',
  locales: ['en', 'de', 'fr'],
  defaultLocale: 'en',
});

Exported types

The following option, result, and engine types are exported alongside the runtime functions:

TypeUsed by
LoadedConfigloadConfig result ({ config, filepath })
LangSyncConfigshape of loaded.config
LangSyncConfigInputdefineConfig input
RunValidateOptionsrunValidate
RunValidateResultrunValidate
NamespacedValidationIssuerunValidate issues
RunSyncOptionsrunSync
RunSyncResultrunSync
RunFindMissingOptionsrunFindMissing
RunFindMissingResultrunFindMissing
MissingEntryrunFindMissing entries
RunTranslateOptionsrunTranslate
RunTranslateResultrunTranslate
TranslationEntryrunTranslate entries
AIProviderrunTranslate provider override
ValidationIssueunderlying validation issue shape
TreeDiffper-file diff in RunSyncResult

On this page