Add to an Existing App
Already have a NestJS backend? Wire Loopstack into it directly. Starting fresh instead? loopstack create scaffolds all of this — module, config, a hello workflow, Docker Compose, and a .env — in one command.
Requirements
- Node.js 20.19+ (or 22 LTS). Loopstack ships as native ESM, which needs the
require(esm)support added in Node 20.19 / 22. - An ESM app. Loopstack is ESM-only (no CommonJS build), so your project must be ESM too —
"type": "module"inpackage.json,module/moduleResolutionset tonodenextintsconfig.json, and.jsextensions on relative imports. A CommonJS project has to migrate to ESM first.
1. Install the module
npm install @loopstack/loopstack-module2. Register the module
Add LoopstackModule to the imports in src/app.module.ts:
import { Module } from '@nestjs/common';import { LoopstackModule } from '@loopstack/loopstack-module';
@Module({ imports: [LoopstackModule.forRoot()],})export class AppModule {}Enable shutdown hooks in src/main.ts so the workflow engine shuts down gracefully — on SIGTERM (a deploy, docker stop) running workflows finish their current transition, stop before the next one and queue their continuation, which the next process picks up:
async function bootstrap() { const app = await NestFactory.create(AppModule); app.enableShutdownHooks(); await app.listen(process.env.PORT ?? 3000);}The drain waits at most SHUTDOWN_DRAIN_TIMEOUT_MS (30 seconds by default) for runs to yield, then closes by force; a second Ctrl+C does the same at once. See Configuration.
Add YAML asset bundling to nest-cli.json so workflow UI configs are included in the build:
{ "compilerOptions": { "assets": ["**/*.yaml"] }}3. Provide Postgres & Redis
Loopstack needs a PostgreSQL and a Redis instance. There are two equally good ways to provide them:
Option A — Docker (quickest locally). The module ships a Compose file for Postgres and Redis:
docker compose -f node_modules/@loopstack/loopstack-module/docker-compose.yml up -dWant the visual Studio UI too? Start it alongside — it’s a separate, optional compose file:
docker compose -f node_modules/@loopstack/loopstack-module/docker-compose.studio.yml up -dOption B — Bring your own. Point the app at any existing Postgres and Redis (managed, hosted, or already running) via .env:
DATABASE_URL=postgres://user:password@host:5432/dbnameREDIS_URL=redis://host:6379CI and coding agents should use Option B (point the URLs at an available instance) and drive workflows from the CLI, not the browser-based Studio.
4. Write your first workflow
Create src/hello/hello.workflow.ts — a single class with one transition:
import { z } from 'zod';import { BaseWorkflow, MessageDocument, Transition, Workflow } from '@loopstack/common';import type { RunContext } from '@loopstack/common';
const InputSchema = z.object({ name: z.string().default('World'),});
type InputArgs = z.infer<typeof InputSchema>;
@Workflow({ title: 'Hello World', description: 'Greets you by name — replace this with your first real workflow.', schema: InputSchema,})export class HelloWorkflow extends BaseWorkflow<InputArgs> { @Transition({ from: 'start', to: 'end' }) async greet(_state: unknown, ctx: RunContext<InputArgs>) { const greeting = `Hello, ${ctx.args.name}! 👋`; await this.documentStore.save(MessageDocument, { role: 'assistant', text: greeting }); this.assignResult({ greeting }); }}Create src/hello/hello.module.ts — @StudioApp groups workflows into an app:
import { Module } from '@nestjs/common';import { StudioApp } from '@loopstack/common';import { HelloWorkflow } from './hello.workflow';
@StudioApp({ title: 'My First App', workflows: [HelloWorkflow],})@Module({ providers: [HelloWorkflow],})export class HelloModule {}Register it in src/app.module.ts:
import { Module } from '@nestjs/common';import { LoopstackModule } from '@loopstack/loopstack-module';import { HelloModule } from './hello/hello.module';
@Module({ imports: [LoopstackModule.forRoot(), HelloModule],})export class AppModule {}5. Run
npm run start:dev # http://localhost:3000Run the workflow from the terminal — the CLI talks to the local backend with no login:
npx @loopstack/cli run hello --arg name=YouIt streams each transition and the result live, and returns CI-friendly exit codes. Prefer a visual UI? Start Studio (step 3) and open http://localhost:5173.
This first workflow is zero-config — no API keys needed. To make a workflow call an LLM, see AI Text Generation.
Next steps
- Core Concepts — workflows, tools, documents, and providers
- Creating Workflows — transitions, guards, state, and wait patterns
- AI Text Generation — add LLM calls to your workflows
zod version (reference)
Loopstack requires zod v4 — it uses the v4-only z.toJSONSchema() API to turn workflow input schemas into JSON Schema. npm 7+ installs it automatically as a peer dependency when you run npm install @loopstack/loopstack-module, so you don’t normally need to install it yourself. Older tutorials may show zod@^3; that won’t resolve against Loopstack’s peer constraint and npm install will fail with ERESOLVE.