LaunchStack: a self-hosted TypeScript engine for AI document workflows
AI-powered StartUp Accelerator Engine built with Next.js, LangChain, PostgreSQL + pgvector. Upload, organize, and chat with documents. Includes predictive missing-document detection, role-based workflows, and page-level insight extraction.
At a glance
- What is it?
- LaunchStack packages ingestion, OCR, RAG, a knowledge graph and LLM routing into ports-based TypeScript packages, with a Next.js app on top. The engine packages are not on npm yet, so adopting it today means running the repository.
- Who is it for?
- Adopt LaunchStack if you want a self-hosted, TypeScript-first document pipeline and are willing to run the repository rather than install published packages, since the engine packages are not yet on npm. Skip it if you need a managed service or a one-command deploy with no Postgres and pgvector to operate.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 28, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem LaunchStack targets: documents that pile up outside any pipeline
Teams accumulate PDFs, Office files and text exports faster than they can organise them. The usual response is a folder structure and a search box, which works until someone needs to ask a question that spans six documents. LaunchStack is aimed at that gap. The README describes it as "a TypeScript engine for AI-native applications" covering ingestion, OCR, RAG, a knowledge graph, LLM abstractions and background jobs, wired into a Next.js reference app.
The audience is narrower than the description suggests. This is for engineers who want to embed these pieces in their own TypeScript codebase, or who want a self-hosted instance they operate themselves. The README is explicit that a deployment is self-hosted unless DEPLOYMENT_MODE=cloud is set, and that the defaults assume self-hosting: usage is recorded but never gated, no telemetry is loaded and no assets come from a CDN. The first person to sign up becomes the owner of the workspace, already verified, with no separate admin bootstrap. If you want a hosted product you sign into, this is not it.
How the pieces fit: a workspace root, a web app, and a worker that does the actual work
The repository is a pnpm workspace, and the README is blunt about the consequence: the root is not an application. It holds no runtime dependencies, no server and no app code, and pnpm dev at the root fails with ERR_PNPM_NO_SCRIPT. Only repo-wide commands live there, such as lint, typecheck, check, format:write and the Changesets scripts. Everything else is targeted with --filter.
The runtime splits across two processes, and this is the part worth understanding before you deploy anything. apps/web is the Next.js app handling UI, auth, command acceptance and synchronous reads. apps/worker is the durable workflow coordinator, listening on port 8020 with /healthz and /readyz endpoints. Ingestion runs in the worker, not in web. The README states plainly that web dev accepts uploads but processes nothing, so documents sit queued forever unless the worker runs alongside it. The docker-compose.yml comments list the ports: 3000 for Next.js, 8020 for the worker, 8288 for the Inngest dashboard, 5433 for PostgreSQL, plus 8000, 8002, 8003 and 8004 for transcription, document conversion, docs editing and PDF rendering services.
The engine itself is organised as ports-based packages: @launchstack/protocol, evidence, application, adapters and a core facade. That structure is the interesting design decision. It means the storage, LLM and parsing concerns sit behind interfaces, and the Next.js app is a reference consumer rather than the product. The README notes that running db:migrate from @launchstack/core applies only the engine migration set, which is what a consumer embedding the engine needs, while a full app needs both sets. That distinction only makes sense if the packages are meant to be used outside this repository, which is the stated intent.
Installing LaunchStack and running it with Docker
The README requires Node 20 or later and pnpm 10.15.1, which corepack enable picks up from the pinned version. Clone the repository, install, and copy the environment file:
git clone https://github.com/Deodat-Lawson/LaunchStack.git
cd LaunchStack
pnpm install
cp .env.example .envTwo variables are mandatory before anything boots. apps/web/src/env.ts refuses to start without DATABASE_URL and BETTER_AUTH_SECRET, and the README suggests generating the secret with openssl rand -base64 32. Chat needs no variable at all: with CHAT_BASE_URL unset it defaults to Google Gemini's OpenAI-compatible endpoint, authenticated with GOOGLE_AI_API_KEY.
The recommended path is Docker through the Makefile. make up-prod starts the lite stack detached at roughly 400MB RAM, and make up-ocr adds Docling for Office documents at roughly 1.2GB:
make up-prod # lite stack, detached (~400MB RAM)
make up-ocr # adds Docling for Office docs, detached (~1.2GB RAM)
make logs # follow logs
make down # stop containers (keeps volumes)
make down-clean # stop + wipe volumesOn Windows without make, the README gives the equivalent Compose invocations directly, including docker compose --env-file .env --profile ocr up --build -d for the OCR profile. It also notes that make up runs in the foreground, so you need a second shell to stop it.
Without Docker, the path is four pnpm commands, and the ordering matters:
pnpm --filter @launchstack/web db:migrate
pnpm --filter @launchstack/core db:seed
pnpm --filter @launchstack/web dev
pnpm --filter @launchstack/worker devThe first applies both migration sets. The second is optional and seeds one company, user and document. The third starts Next.js on port 3000, and the fourth starts the durable worker on 8020. If you skip the worker, uploads queue and never process. There is also an optional Inngest dev server on 8288, but the README says it is only needed for the Inngest-hosted background verticals, not for ingestion.
One detail that will save time: .env.example points DATABASE_URL at localhost:5433/pdr_ai_v2, which is what Compose publishes, so the Docker and non-Docker paths share one database by default. If you run your own Postgres on 5432, use the commented line instead. Your Postgres needs the pgvector extension available, because the migration runner enables it and exits non-zero on stock Postgres.
Chat configuration is one endpoint, not a provider list
The chat setup is the most opinionated part of the configuration, and it will surprise anyone used to per-vendor API keys. There is no OPENAI_API_KEY, OPENROUTER_API_KEY or OLLAMA_BASE_URL variable that configures chat. The README explains the reasoning: a key names who you are, not where the request goes, and every one of those providers speaks the same OpenAI chat-completions protocol, so each is reached through CHAT_BASE_URL plus CHAT_API_KEY like any other endpoint. None of those bare variables is forwarded to the Gemini default either.
Only AI_BASE_URL and AI_API_KEY, a straight rename of the canonical pair, are still translated, and the README says that happens with a deprecation warning. Model ids and route assignments live in a mounted chat-models.yaml rather than in environment variables, which the Compose file confirms through CHAT_MODELS_CONFIG. This is a clean design if you already run a gateway in front of your models. It is friction if you expected to paste a provider key and go.
Where LaunchStack is the wrong choice
The engine packages are not on npm. The README states this directly: @launchstack/protocol, evidence, application, adapters and the core facade are not yet published, and the first release will publish them together through the Changesets flow in release.yml. Until that release lands, the README says to consume the engine by running this repository. If your requirement is npm install @launchstack/core in an existing project, that requirement is unmet today, and the repository does not document a date for it.
The operational surface is the second constraint. You need a Postgres with pgvector, and the migration runner exits non-zero without it. You need the worker process running or nothing ingests. The OCR path adds roughly 800MB of RAM for Docling, and the Compose comments say that without the ocr profile, /convert returns a typed 503 while text-file ingestion still works. That is a reasonable degradation, but it means PDF and Office parsing is a deliberate resource commitment, not a default.
There is also a deployment mode that can strand an instance. The .env.example warns that under DEPLOYMENT_MODE=cloud, the token ledger gates uploads on a balance and nothing in the product can add credits, so a self-hosted instance set to cloud stops accepting documents for good once its signup grant runs out. Self-hosted mode still records usage at /api/credits/usage but never refuses work. Setting that variable carelessly is the kind of mistake that only shows up weeks later.
Finally, the README does not document rollback, and the migration command is the same one CI, Docker and the production image build run. Nothing else creates schema. If you need a documented downgrade path before you touch a production database, that path is not described here.
How LaunchStack differs from a Python RAG stack
The obvious alternative is a Python stack built around LangChain with a vector store such as pgvector, Qdrant or Chroma, plus a task queue for ingestion. LaunchStack uses LangChain too, and pgvector as well, so the difference is not the algorithm. It is the language and the packaging.
A Python RAG stack tends to be a set of libraries you import into an application you write, with the orchestration living in your code. LaunchStack inverts that: it ships the orchestration as an application, with a web process for reads and command acceptance and a separate worker for durable execution, and it treats the engine packages as something a TypeScript codebase embeds. If your team writes TypeScript and wants the pipeline to be a running service rather than a library graph, that inversion is the point. If your team writes Python, or you want to assemble the pieces yourself, the Python route gives you more freedom and a much larger pool of examples. The trade is that you write the orchestration, the worker, the migration flow and the auth yourself.
The self-hosting defaults are the other differentiator. A deployment is self-hosted unless you opt out, no telemetry is loaded and no assets come from a CDN. That is a deliberate posture, and it is the reason the first signup becomes the verified workspace owner with no separate admin bootstrap. Projects that assume a hosted control plane do not make that choice.
Licence, maintenance and the cost of upgrading
LaunchStack is Apache-2.0, and the repository carries a THIRD_PARTY_LICENSES.md alongside the LICENSE file. Apache-2.0 permits commercial use and modification, and it includes a patent grant, but it also carries notice and attribution obligations that a permissive licence like MIT does not. This is not legal advice; if you redistribute a modified version, read the licence text and the third-party file rather than assuming MIT-equivalent terms.
The engine packages are versioned through Changesets, with a release script that builds the packages under packages/* and @launchstack/pipelines before publishing. That means upgrades will arrive as versioned package releases once the first one lands, and the repository already validates the packed tarball with publint and a Node-ESM loadability check for every subpath. That is a stronger release gate than most projects at this stage.
Until then, upgrading means pulling the repository and re-running migrations. The README states that db:migrate is the same command CI, Docker and the production image build run, and that nothing else creates schema. So the upgrade cost is bound to migration discipline rather than to a package manager. The last push to the repository was on 2026-09-08, and the only release listed is v1.0.0 from 2026-04-20. There is no published deprecation policy and no documented rollback, so treat schema changes as the thing you plan around.
Editorial conclusion
Adopt LaunchStack if you want a self-hosted, TypeScript-first document pipeline and are willing to run the repository rather than install published packages, since the engine packages are not yet on npm. Skip it if you need a managed service or a one-command deploy with no Postgres and pgvector to operate. Before committing, verify that your Postgres has the pgvector extension, that you can run the worker alongside the web app, and that CHAT_BASE_URL points at an endpoint you control.
Frequently asked questions
Is LaunchStack available on npm?
No. The README states that the engine packages (@launchstack/protocol, evidence, application, adapters and the core facade) are not yet on npm, and that the first release will publish them together through the Changesets flow in release.yml. Until then, the README says to consume the engine by running the repository.
Which environment variables does LaunchStack require to boot?
apps/web/src/env.ts refuses to boot without DATABASE_URL and BETTER_AUTH_SECRET. Chat needs no variable at all, because with CHAT_BASE_URL unset it defaults to Google Gemini's OpenAI-compatible endpoint authenticated with GOOGLE_AI_API_KEY.
Can I run LaunchStack without Docker?
Yes. The README gives a non-Docker path using pnpm: run db:migrate from @launchstack/web, optionally db:seed from @launchstack/core, then start @launchstack/web dev on port 3000 and @launchstack/worker dev on port 8020. Your Postgres needs the pgvector extension available, because the migration runner enables it and exits non-zero on stock Postgres.
Why do my uploaded documents stay queued in LaunchStack?
Because ingestion runs in the worker, not in the web app. The README states that web dev is plain next dev, accepts uploads but processes nothing, and that you must run the worker alongside it or documents will sit queued forever.
Does LaunchStack support OpenAI or Ollama directly?
Not through per-vendor variables. The README says a bare OPENAI_API_KEY, OPENROUTER_API_KEY or OLLAMA_BASE_URL will not configure chat, and that each provider is reached through CHAT_BASE_URL because they all speak the OpenAI chat-completions protocol. Only AI_BASE_URL and AI_API_KEY are still translated, with a deprecation warning.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/deodat-lawson-launchstack)