Skip to content

Quick start

Create a project, run a small extraction and check the result. Choose the default feature-extraction template and skip the provider to try it offline with recorded answers.

Terminal window
npm create nola

Nola requires Node ≥ 22.18. The scaffolder warns if your Node version is too old.

Enter a project name, or press Enter to use nola-app, then choose a template:

Template What it demonstrates
feature-extraction (default) Extract typed data with top-level asks in one .tsi file. Includes recorded answers for offline use.
function-calling Let an ask fill the arguments of an async function in a neighboring .ts file. Includes recorded answers.
agent-loop Run a top-level while loop whose ask is typed as a Problem or null, with a context statement read again on every pass. Uses a mock provider.
typescript-interop Import an infer function from plain TypeScript and await its result. Includes recorded answers.
triage-ticket Triage a ticket with typesafe.ai. Requires TYPESAFE_API_KEY.
empty Start with configuration and a stub src/main.tsi to write your program in. Includes no replay ledger.

More examples… opens the remaining curated examples. Every template except empty is one of the examples in the Nola repository, fetched at the release tag that matches your CLI version, so scaffolding them needs network access. You can also name a template directly: npm create nola my-app -- --template extract-resume.

The next prompt, Select an inference provider:, determines where answers come from:

  • nola: dev gives you 25 free hosted runs. The scaffolder requests a trial key, saves it as NOLA_API_KEY in the git-ignored .env file and sets model: "nola". Nola’s service chooses the model.
  • OpenAI, Anthropic, Gemini or typesafe.ai configures that vendor. Copy the generated .env.example to .env and add your key before running the project. The configs use openai("gpt-5-mini"), anthropic("claude-sonnet-4-5"), google("gemini-2.5-flash") or typesafe(). The typesafe.ai option supports only literal unions and booleans, so it cannot run every ask in feature-extraction.
  • Skip for now keeps the template’s configuration. feature-extraction, function-calling and typescript-interop use a replay ledger and agent-loop a mock provider, so all four work offline.

Each machine can request one anonymous trial. If yours already has a trial key, choosing nola: dev opens the browser to sign you in and creates a key on your account instead. If sign-in fails, the provider menu returns. You can also sign in later with npx nola-lang login. For a non-interactive run, pass --provider nola to request a key or --provider none to skip; --trial and --no-trial are equivalent shortcuts.

By default, the project includes VS Code debugging settings and the Nola skill for coding agents. The skill lives at .agents/skills/nola/, with a relative symlink at .claude/skills/nola for Claude Code. Use --ide none to skip editor files, --agents none to skip the skill, or --agents claude,universal,agents-md to also embed the skill in AGENTS.md. See Editor setup and The nola CLI.

The final prompt offers to install dependencies and open VS Code. If you accept, the entry file opens with a comment explaining how to run it with F5 and set a breakpoint. Without the code command on your PATH, the prompt offers only to install dependencies.

Terminal window
cd my-app
npm install
npm start

Use your chosen folder name in place of my-app. If the scaffolder already installed dependencies, you can skip npm install.

For feature-extraction, npm start runs nola run src/main.tsi. Answers come from the provider you chose, or from nola.replay.jsonl if you skipped provider setup. Here is the program:

src/main.tsi
`You read short professional bios. Answer from the text alone; never invent facts.`
interface Person {
name: string;
age: number;
employer: string;
job: string;
}
// A `.` binding is context: every ask below sees its value.
const .message = "Alice Smith, 32, is a staff engineer at Acme Corp working on distributed systems.";
// `ask` works at the top level: this file is the whole program.
const person = ask `the person described in the text`: Person;
// A binding declared after an ask is visible to the asks that follow, so one answer feeds the next.
const .role = person.job;
const seniority = ask `the seniority level the role implies`: "junior" | "mid" | "senior" | "staff";
console.log(JSON.stringify({ ...person, seniority }));

Expected output:

Terminal window
{"name":"Alice Smith","age":32,"employer":"Acme Corp","job":"staff engineer","seniority":"staff"}
  • The template literal on the first line is a context statement: every ask below it, here both, sees its text.
  • const .message and const .role are contextual bindings. Their values are available to subsequent asks. Only the second ask sees .role, which was declared after the first ask returned.
  • ask `…`: Person is an extractor. Nola derives a schema from Person, asks for a matching value and validates the reply. Extractors can be resolved at the top level with ask; a bare await cannot resolve a raw extractor.

The function-calling template uses a call intent to fill the arguments of createTicket in src/tickets.ts and run it. The typescript-interop template puts extraction in an infer function, which src/main.ts imports and awaits. Use that structure when you want to call the same inference from other parts of an application. Project anatomy explains both layouts.

To use your own OpenAI key, edit nola.config.ts:

nola.config.ts
import { openai } from "@nola-lang/providers";
import { defineConfig } from "@nola-lang/runtime";
export default defineConfig({
// Reads OPENAI_API_KEY from the environment at the first ask.
model: openai({ model: "gpt-5-mini" }),
});

Put OPENAI_API_KEY=… in .env at the project root, then run npm start again. If the scaffold supplied .env.example, copy it to .env first. The development loader reads this file; built applications use the process environment. See Providers for anthropic({ model }), google({ model }) and other options.

To get a Nola key for another project, run npx nola-lang key. It signs you in if the machine’s trial has been used and offers to save the key in that project’s .env; --print prints only the key. After the free runs are used, asks fail with Your 25 free Nola runs are complete. Run npx nola-lang account to open your account, manage keys or add balance.

If you started offline, editing a prompt or type changes the request fingerprint. The recorded answer then no longer matches, and replay fails with NOLA3008. Switch to a live provider or record a new ledger before continuing.

Terminal window
npx nola-lang check # type-checks .tsi and .ts together, positions mapped back to .tsi
npx nola-lang build # lowers every .tsi into dist/ (+ a self-configuring dist/nola.config.js)

nola build writes dist/src/main.tsi.js, its source map and declaration file, and dist/nola.config.js. The built module imports the config, so you can run it with node dist/src/main.tsi.js.

The build compiles .tsi files only. If you chose typescript-interop, its plain .ts entry needs a separate build step. Deploying shows how to arrange the output.

nola-lang is a devDependency; the app itself depends on @nola-lang/runtime and @nola-lang/providers.

Next: Add Nola to an existing project