Skip to content

Config File

All Lucerna settings live in a lucerna.config.ts file. The MCP server and every CLI command find this file automatically by searching upward from the project root — so a config at a monorepo root is found from any subdirectory.

If no config file exists, one is created automatically the first time you run index, watch, or mcp-server.

Lucerna checks for these filenames in order:

  • lucerna.config.ts
  • lucerna.config.js
  • lucerna.config.mjs
lucerna.config.ts
import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: {
provider: "voyage",
model: "voyage-code-3",
apiKey: process.env.VOYAGE_API_KEY!,
},
});

defineConfig() is an identity function that gives you TypeScript autocomplete and type-checking — no need to import types separately.

Lucerna walks up the directory tree from the project root until it finds a config file or reaches the filesystem root. This means:

  • A config at /workspace/lucerna.config.ts is found when running from /workspace/packages/my-app
  • Each project can have its own config, or a monorepo can share one at the root
interface LucernaConfig {
/**
* Embedding provider config or custom EmbeddingFunction instance.
* false = disable semantic search (BM25 only).
* undefined = semantic search disabled (no provider configured).
*/
embedding?: EmbeddingProviderConfig | EmbeddingFunction | false;
/**
* Reranking provider config or custom RerankingFunction instance.
* false or undefined = no reranking.
*/
reranking?: RerankingProviderConfig | RerankingFunction | false;
/**
* Glob patterns (relative to project root) of files to index.
* Default: ["**\/*"] (all files — unrecognised extensions produce no chunks).
*/
include?: string[];
/**
* Additional glob patterns to exclude on top of built-in exclusions
* (node_modules, .git, dist, lock files, binary files, etc.).
*/
exclude?: string[];
}

Pick the provider matching your credentials and pass credentials via process.env to keep them out of source control.

import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: { provider: "voyage", model: "voyage-code-3", apiKey: process.env.VOYAGE_API_KEY! },
});
import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: { provider: "openai", model: "text-embedding-3-small", apiKey: process.env.OPENAI_API_KEY! },
});
import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: { provider: "cohere", model: "embed-english-v3.0", apiKey: process.env.COHERE_API_KEY! },
});
import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: { provider: "jina", model: "jina-embeddings-v3", apiKey: process.env.JINA_API_KEY! },
});
import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: { provider: "mistral", model: "mistral-embed", apiKey: process.env.MISTRAL_API_KEY! },
});
import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: { provider: "gemini", model: "text-embedding-004", apiKey: process.env.GOOGLE_API_KEY! },
});
import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: { provider: "ollama", model: "nomic-embed-text" },
// Optional: host defaults to http://localhost:11434
// embedding: { provider: "ollama", model: "nomic-embed-text", host: "http://my-server:11434" },
});
import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: { provider: "lmstudio", model: "text-embedding-nomic-embed-text-v1.5" },
// Optional: baseUrl defaults to http://localhost:1234
});
import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: {
provider: "cloudflare",
accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
apiKey: process.env.CLOUDFLARE_API_TOKEN!,
model: "@cf/baai/bge-large-en-v1.5", // optional
},
});

Uses Application Default Credentials (ADC) for automatic token refresh. Run gcloud auth application-default login once locally. For CI/CD, set GOOGLE_APPLICATION_CREDENTIALS to a service account key file path (or pass it via keyFile).

import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: {
provider: "vertex",
model: "text-embedding-005",
project: process.env.GOOGLE_CLOUD_PROJECT!,
location: "us-central1", // optional, default: us-central1
// keyFile: process.env.GOOGLE_APPLICATION_CREDENTIALS, // explicit service account key (optional)
},
});

Add optional reranking to improve result precision:

import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
embedding: { provider: "voyage", model: "voyage-code-3", apiKey: process.env.VOYAGE_API_KEY! },
reranking: { provider: "voyage", apiKey: process.env.VOYAGE_API_KEY! },
});

Supported reranking providers: voyage, cohere, jina, gemini, cloudflare, vertex.

Restrict which files get indexed:

import { defineConfig } from "@upstart.gg/lucerna";
export default defineConfig({
include: ["src/**/*", "tests/**/*"],
exclude: ["**/*.test.ts", "**/fixtures/**", "**/__snapshots__/**"],
});

include defaults to ["**/*"]. Built-in exclusions (node_modules, .git, dist, lock files, binary files, and the .lucerna storage directory) are always applied regardless of exclude.

For advanced use cases, pass a class instance directly instead of a provider config object:

import { defineConfig } from "@upstart.gg/lucerna";
import { MyCustomEmbeddings } from "./my-embeddings.js";
export default defineConfig({
embedding: new MyCustomEmbeddings({ model: "custom-v1" }),
});

See Custom Providers for how to implement the EmbeddingFunction and RerankingFunction interfaces.