# NodeCG: broadcast graphics built on plain web pages

> NodeCG is an MIT-licensed TypeScript framework for broadcast graphics, and its central design choice is that a graphic is an ordinary webpage. It ships a server, a dashboard, a browser source and a data API, and it runs inside OBS Studio, vMix, XSplit or CasparCG.

**nodecg/nodecg** — Create broadcast graphics using Node.js and a browser

- Repository: https://github.com/nodecg/nodecg
- Website: https://nodecg.dev
- Stars: 1,307 · Forks: 164
- Language: TypeScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/nodecg-nodecg

## A graphic is a webpage, and that is the whole idea

NodeCG is a broadcast graphics framework and application, and the sentence that explains it is this one: NodeCG has no graphics or drawing primitives of its own. Instead, NodeCG provides a structure for your code and an API to facilitate moving data between the dashboard, the server, and your graphics.

It makes few assumptions about how to code a graphic and gives you freedom to use whatever libraries, frameworks, tools and methodologies you want. The README is blunt about why this matters: NodeCG graphics are just webpages, there is absolutely nothing special or unique about them, and this is their greatest strength.

The stated goal is to remain as close to the web platform as possible, and the reasoning is about access rather than elegance. New APIs and capabilities are continually added to the web platform, and NodeCG developers should have access to the entirety of what the web can offer, so the framework deliberately does not build many abstractions on top of it.

That has a practical consequence. A NodeCG graphic is a browser page, so it can run anywhere a browser can render, and the list is concrete: OBS Studio, vMix, XSplit, and CasparCG from version 2.2.0. If your streaming software is not on the list, the README suggests a check rather than a workaround, opening whatversion.net/chrome as a browser source to see which browser engine it uses.

The licence is MIT, the primary language is TypeScript, and the repository is not archived with the last push on 2026-06-28.

## Where it came from, and the two goals that shaped it

The history explains a lot about the project's priorities.

NodeCG was originally created to provide real-time broadcast graphics for Tip of the Hats, an all-volunteer charity fundraiser that had a budget of $0 for its first several years. The first goal the project states is making broadcast graphics, also known as character generation or CG, more accessible, since historically they required expensive hardware, expensive software, or both. The claim that follows is that it is now possible to create an ambitious broadcast using entirely free software and consumer hardware.

The second goal is supporting broadcasts of any size and ambition. NodeCG's roots are in small broadcasts with no budget, and more recently it has begun seeing use in increasingly elaborate productions. The belief is that one set of tools should scale from the smallest show to the largest, and it should work whether you use OBS for everything or a hardware switcher with a traditional key and fill workflow.

That last sentence is the one to hold on to when evaluating it. NodeCG is positioned as a component of a graphics system rather than as the system itself, and a production that runs a dedicated render server and a switcher is a legitimate deployment for it, not an edge case.

The acknowledgements name the people and projects behind it, including Atmo for the original dashboard concept and code, and Alex Van Camp as the designer and developer of toth-overlay, the base on which NodeCG was built.

## A monorepo of five workspaces

The repository is a monorepo, and the manifest is called nodecg-monorepo and is marked private, with npm workspaces listed explicitly.

The workspaces are internal-util, database-adapter-types, database-adapter-sqlite-legacy, cli and nodecg itself. The naming of the database adapter packages is the interesting part, because it shows the shape of the persistence layer. There is a types package, which is the contract, a legacy SQLite adapter, and the absence of an equally-named Postgres adapter in the workspace list is itself informative about which backend the project treats as current.

The release tags reflect that split, with nodecg-v2.8.0, internal-util-v2.7.2 and database-adapter-sqlite-legacy-v2.7.2 published separately on the same day, 2026-06-28. A `.release-please-manifest.json` and a `release-please-config.json` in the tree confirm that the versioning is handled by release automation rather than by hand.

Outside the workspaces, the root holds `bundles/` for the graphics packages, `db/` for the database, `docs/`, `media/`, `scripts/`, an `index.js` entry point, a `Dockerfile`, and TypeScript configuration in `tsconfig.json` and `tsconfig.typecheck.json`, with a separate `vitest.config.mts` for the test runner.

The tooling is current rather than legacy. `tsdown` is the bundler, `typescript` sits at 5.9, `vitest` at 4, and `eslint` at 9 with `eslint-plugin-simple-import-sort` for import ordering. The `effect` packages and `jiti` are in the dev dependencies, and the package manager is pinned to npm 11.6.2 with its full integrity hash.

## Running it from a clone

The README's development block is the whole setup sequence.

```bash
# Clone the repository
git clone https://github.com/nodecg/nodecg.git
cd nodecg

# Install dependencies
npm install

# Run auto-rebuild + type-check on file changes
npm run dev

# Build all workspace packages
npm run build

# Run tests
npx vitest run

# Start NodeCG
npm start
```

The scripts in the manifest fill in the details. `npm run dev` is `run-p watch typecheck-watch`, running the `tsdown --watch --no-clean` rebuild and the TypeScript project build in watch mode in parallel, so the two do not fight over the output directory. `npm run build` is a plain `tsdown` build, `npm run typecheck` is `tsc -b tsconfig.typecheck.json`, and `npm start` is `node index.js`.

There is also a separate `typetest` script that delegates into the nodecg workspace, so type-level tests are part of the toolchain rather than an afterthought, and `lint` runs eslint together with a prettier check, with a matching `fix` script.

The container route is the Dockerfile, which is a four-stage build on `node:22-slim`. It separates a build stage that compiles the workspaces, an npm stage that installs production dependencies only with `npm ci --omit=dev`, and a runtime stage that copies the built output in. The runtime image creates the `cfg`, `bundles`, `logs`, `db` and `assets` directories, declares the last three as volumes to persist, exposes port 9090, and runs `node /opt/nodecg/index.js` directly, with a comment in the Dockerfile noting that using node directly is slightly faster than using `nodecg start`.

Both stages set `PUPPETEER_SKIP_DOWNLOAD` and the build stage also sets `PUPPETEER_SKIP_CHROMIUM_DOWNLOAD`, which keeps a browser binary out of the image.

## What NodeCG does not do

The boundary of the tool is easy to state and worth stating, because the name invites assumptions.

NodeCG draws nothing. There are no drawing primitives, no canvas abstraction, no scene graph, no timeline of its own. A graphic is a webpage, so the composition, the animation and the type are all your code, and the framework's job is to get your data to the page and to move state between the dashboard, the server and the graphics.

The dashboard is the operator side, and the acknowledgements credit Atmo for the original dashboard concept, which tells you the dashboard is a first-class part of the system rather than an afterthought. It is where an operator changes state and the graphics react.

The second boundary is the browser source. The listed hosts, OBS Studio, vMix, XSplit and CasparCG, all have to support a browser source with a recent engine, and the README's advice for anything else is to check the engine version rather than to expect support. That is a real constraint for a studio on older broadcast software, and it is the one most likely to end an evaluation.

The third boundary is operational. NodeCG is a server. It holds a database, it serves the dashboard, it runs the bundles, and it has to be running for the graphics to have data. A single-person show needs that server to be one more thing that can go down on stream day, which the Docker image and its volume layout address but do not remove.

## Conclusion

NodeCG fits a small broadcast team with no budget for broadcast software licences, or a studio that wants graphics written with the web tools it already knows, and that will run a Node server alongside its streaming software. It does not fit a pipeline built around a hardware switcher with a key and fill workflow and no browser source, and it is not a rendering engine, since it draws nothing itself. Before adopting it, run `npm install`, `npm run build` and `npm start` in a clone, check the browser engine version of your streaming software with whatversion.net/chrome, and read the contributor guide on nodecg.dev before changing core code.

## FAQ

### What is NodeCG?

It is a broadcast graphics framework and application for writing complex, dynamic broadcast graphics using the web platform. It has no graphics or drawing primitives of its own, and instead provides a structure for your code and an API for moving data between the dashboard, the server and your graphics.

### Which streaming software can run NodeCG graphics?

OBS Studio, vMix, XSplit and CasparCG from version 2.2.0. For other software, NodeCG graphics need a modern browser engine, and the README suggests checking whatversion.net/chrome as a browser source to see which engine it uses.

### How do I build and run NodeCG from source?

Clone the repository, run `npm install`, then `npm run build` to build all workspace packages, `npx vitest run` for the tests and `npm start` to launch NodeCG. `npm run dev` runs an auto-rebuild and type-check on file changes.

### What does the NodeCG Docker image do?

It is a four-stage build on node:22-slim that compiles the workspaces, installs production dependencies only, and copies the built output into a runtime image. It creates cfg, bundles, logs, db and assets directories, persists the last three as volumes, exposes port 9090 and runs node /opt/nodecg/index.js.

### Is NodeCG still maintained?

The repository is not archived and the last push was on 2026-06-28, the same day as the nodecg-v2.8.0, internal-util-v2.7.2 and database-adapter-sqlite-legacy-v2.7.2 tags. The project is MIT licensed and maintained by Matt McNamara and Keiichiro Amemiya.

## Sources

- [License: MIT](https://github.com/nodecg/nodecg/blob/main/LICENSE)
- [nodecg/nodecg on GitHub](https://github.com/nodecg/nodecg)
- [Project website](https://nodecg.dev)
- [README](https://github.com/nodecg/nodecg/blob/main/README.md)
- [Releases](https://github.com/nodecg/nodecg/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/nodecg-nodecg
