Monorepo
Prerequisites
Section titled “Prerequisites”Personal experience
Section titled “Personal experience”Depending on the kind of contribution you’re interested in, the following experience is recommended:
- Deep experience with TypeScript (incl. type-level programming)
- Solid working knowledge of Effect-TS — LiveStore is
implemented on top of Effect and makes heavy use of its primitives (
Effect,Layer,Schema,Stream,Context.Reference,Ref, etc.). Willingness to ramp up is acceptable, but most non-trivial contributions assume fluency. - Experience with TypeScript monorepo setups
- Experience with distributed systems
Required tooling: Nix + devenv
Section titled “Required tooling: Nix + devenv”LiveStore requires Nix with devenv
to manage all development dependencies (Node.js, Bun, pnpm, oxlint, OTEL stack,
Playwright browsers, etc.). Enter the development shell with devenv shell.
Why this is a hard requirement
Section titled “Why this is a hard requirement”LiveStore is developed alongside a family of projects that share tooling
through effect-utils
— a Nix flake that provides the exact oxlint (with custom plugins),
genie config generator, megarepo CLI, OTEL dashboards, and
Playwright integration used here. Standing this up outside of Nix/devenv
means reimplementing a moving target and drifting from CI.
By requiring Nix + devenv we get:
- Version parity with CI and every other LiveStore/effect-utils project — the same compiler, linter, and task-runner versions everywhere.
- Reproducible builds — no “works on my machine” drift between contributors.
- Single source of truth — tool versions live in
devenv.nix, not scattered across READMEs.
Install Nix
Section titled “Install Nix”We recommend the Determinate Nix Installer — it sets sane defaults, enables flakes out of the box, and is easy to uninstall. Any Nix install with flakes enabled works; Determinate is simply the path of least resistance.
After installing Nix, install devenv following its install guide.
(Optional) If you prefer the dev environment to auto-load when you cd
into the repo, also install direnv — the repo ships
an .envrc that wires devenv into direnv. Not required.
Manual setup (discouraged)
Section titled “Manual setup (discouraged)”It is technically possible to set up the toolchain manually (Node.js, Bun, pnpm, etc.), but this path is not supported: you’ll diverge from CI, miss linter plugins, and have to track tool versions by hand. Use Nix + devenv unless you have a very specific reason not to.
Initial setup
Section titled “Initial setup”git clone git@github.com:livestorejs/livestore.gitcd livestoredevenv shellEntering the shell builds the Nix environment, puts the full toolchain
(Node.js, Bun, pnpm, mono, oxlint, oxfmt, etc.) on $PATH, and
runs the project setup task (which installs pnpm deps, regenerates
genie outputs, and builds TypeScript).
Working with devenv
Section titled “Working with devenv”devenv shell is the primary entry point. Everything the repo provides —
packages, env vars, tasks, background processes — comes from devenv.nix
and is surfaced through the devenv CLI:
devenv shell— open an interactive subshell with the full dev environment. Typeexitto leave. Re-run after closing the terminal.devenv shell <cmd> [args...]— run a single command inside the environment without staying in the subshell. Useful for scripts and CI (devenv tasks run ts:check).devenv tasks list— list all defined tasks (see Common commands below for the most-used ones).devenv tasks run <task>— run a task directly. The project’s pre-commit hook uses this (devenv tasks run check:quick).devenv up— start long-running processes defined indevenv.nix(e.g. the local OTEL stack — see OpenTelemetry setup).devenv info— print a summary of what the current environment provides (packages, env vars, processes, tasks). Handy when debugging.
See the devenv docs for the full CLI reference.
General notes
Section titled “General notes”- TypeScript
- LiveStore tries to follow the strictest TypeScript rules possible to ensure
type safety and avoid subtle bugs.
- LiveStore also makes heavy use of TypeScript project references.
- LiveStore tries to follow the strictest TypeScript rules possible to ensure
type safety and avoid subtle bugs.
- Package management
- This project uses pnpm to manage the workspace.
- LiveStore is primarily developed in VSCode/Cursor.
- Testing
- LiveStore uses Vitest for most tests and Playwright for browser tests.
Notable used tools / technologies
Section titled “Notable used tools / technologies”- TypeScript
- Effect
- pnpm
- Bun
- Vitest
- Playwright
- OpenTelemetry
- wa-sqlite (included as git subtree) - see wa-sqlite management
- Nix
- devenv
Environment variables
Section titled “Environment variables”Project env vars are declared in devenv.nix and set by devenv shell.
For local overrides (credentials, custom service endpoints), export them
in your parent shell before running devenv shell — they propagate
through. If you use direnv, the repo’s .envrc sources a git-ignored
.envrc.local for the same purpose.
Common commands
Section titled “Common commands”Tasks are run from the repo root with devenv tasks run <task>. Run it
directly from any shell; if you’d rather have the underlying tools on
$PATH, enter devenv shell first (or prefix a single command with
devenv shell). Most-used tasks:
devenv tasks run ts:build/devenv tasks run ts:build-watch— build TypeScript across the monorepodevenv tasks run ts:check— run the TypeScript build/checkdevenv tasks run lint:full/devenv tasks run lint:full:fix— run (and auto-fix) lint + formatdevenv tasks run test:unit/devenv tasks run test:perf/devenv tasks run test:integration:*— run test suitesdevenv tasks run docs:dev/devenv tasks run docs:build/devenv tasks run docs:deploy— docs workflowsdevenv tasks run examples:install/devenv tasks run examples:test/devenv tasks run examples:deploy— example workflows
Release workflows are documented in
context/03-delivery/02-release/release-workflows-runbook.md.
Tasks to run before committing
Section titled “Tasks to run before committing”A pre-commit hook runs devenv tasks run check:quick automatically, but
you should also run the following manually for a tighter feedback loop:
devenv tasks run lint:full:fix— auto-fix lint + format issuesdevenv tasks run ts:check— ensure TypeScript passesdevenv tasks run test:unit(and relevantdevenv tasks run test:integration:*suites) — run tests
Examples
Section titled “Examples”- Once you’ve set up the monorepo locally, you’ll find all examples in the
/examplesdirectory. - All examples are self-contained and can be run independently.
- Examples use explicit version dependencies (e.g.,
0.3.2-dev.0) for LiveStore packages. - Examples are not part of the monorepo TypeScript build system to maintain independence.
- Each example has its own TypeScript configuration that’s independent of the monorepo build system.
Making changes to examples
Section titled “Making changes to examples”- Make your desired changes directly in
/examples/<example-name>. - Test your changes by running the example (e.g.,
pnpm devin the example directory). - Commit your changes.
OpenTelemetry setup
Section titled “OpenTelemetry setup”As a local OpenTelemetry setup, we recommend the docker-otel-lgtm setup.
Export the following before entering devenv shell (or in your
.envrc.local if you use direnv):
export VITE_GRAFANA_ENDPOINT="http://localhost:30003"export GRAFANA_ENDPOINT="http://localhost:30003"export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"export VITE_OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"TypeScript
Section titled “TypeScript”- Each package has its own
tsconfig.jsonfile which extends the roottsconfig.base.json. - This project makes heavy use of TypeScript project references.
Package management
Section titled “Package management”- This project uses pnpm to manage the workspace.
- We’re using the
workspace:*protocol to link packages together. - We should try to keep dependencies to an absolute minimum and only add them if we absolutely need them.
- We also need to manually add peer dependencies for each package.
- We should try to avoid duplicate dependencies across the monorepo as much as possible as duplicate dependencies can lead to a lot of issues and pain.
- Many
package.jsonfiles are generated bygeniefrom.genie.tssources — edit the.genie.tsand rundevenv tasks run genie:run(or let the pre-commit hook run it) rather than editing generatedpackage.jsonfiles directly. - For updating dependencies across the monorepo, see
context/03-delivery/02-release/dependency-management.md(catalog policy, peer-dep handling, validation).
Notes on external dependencies
Section titled “Notes on external dependencies”LiveStore tries to use as few external dependencies as possible. Given LiveStore is built on top of Effect, which can be considered a standard library for TypeScript, it should handle most use cases.
Notes on some packages
Section titled “Notes on some packages”The following packages need to be updated with extra care:
react/react-domas we need to move in lockstep with Expo / React Native (currently pinned to 19.1.0)effect(currently pinned to 3.19.12)
Effect
Section titled “Effect”- LiveStore makes heavy use of the Effect library and ecosystem throughout the implementation of the various packages.
- Effect is not imposed on the app developers using LiveStore but where it makes
sense, LiveStore is also exposing a Effect-based API (e.g.
createStore).
Updating dependencies
Section titled “Updating dependencies”See dependency-management.md for the full workflow.
Notes on monorepo structure
Section titled “Notes on monorepo structure”- The
@livestore/utilspackage re-exports many common modules/functions (e.g. fromeffect) in order to- Reduce the number of direct dependencies for other packages
- Allows for convenient extension of modules (e.g. adding methods to
Effect.___,Schema.___, …)
The LiveStore docs are built with Astro Starlight.
Related external repos
Section titled “Related external repos”- Fork of wa-sqlite with Nix build setup included as git subtree.
- DevTools distributable assets are consumed through public artifact releases; this repository should not contain non-public DevTools source.