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.
1. Create a project
Section titled “1. Create a project”npm create nolapnpm create nolayarn create nolabun create nolaNola 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_KEYin the git-ignored.envfile and setsmodel: "nola". Nola’s service chooses the model. - OpenAI, Anthropic, Gemini or typesafe.ai configures that vendor. Copy the generated
.env.exampleto.envand add your key before running the project. The configs useopenai("gpt-5-mini"),anthropic("claude-sonnet-4-5"),google("gemini-2.5-flash")ortypesafe(). The typesafe.ai option supports only literal unions and booleans, so it cannot run every ask infeature-extraction. - Skip for now keeps the template’s configuration.
feature-extraction,function-callingandtypescript-interopuse a replay ledger andagent-loopa 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.
2. Run it
Section titled “2. Run it”cd my-appnpm installnpm startUse 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:
`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:
{"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 .messageandconst .roleare contextual bindings. Their values are available to subsequent asks. Only the second ask sees.role, which was declared after the first ask returned.ask `…`: Personis an extractor. Nola derives a schema fromPerson, asks for a matching value and validates the reply. Extractors can be resolved at the top level withask; a bareawaitcannot 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.
3. Switch on a real provider
Section titled “3. Switch on a real provider”To use your own OpenAI key, edit 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.
4. Check and build
Section titled “4. Check and build”npx nola-lang check # type-checks .tsi and .ts together, positions mapped back to .tsinpx 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.
What to read next
Section titled “What to read next”- Project anatomy — what every file in the scaffold is for.
- Add Nola to an existing project — use Nola in an application you already have.
- Editor setup — IntelliSense and F5 debugging in
.tsi. - The mental model — the five ideas the language rests on.
- Examples on GitHub — ten runnable projects.