Source: https://learn.nodegx.io/advanced/how-nodegx-stores-an-app
Summary: What is inside a NodeGX project folder, and how Claude reads, checks and writes it.

# How NodeGX stores an app

A NodeGX project is a folder of plain text files. Claude reads and changes those files through the NodeGX connector, which checks every change before it is saved.

## What is in the folder

A recent project looks like this (trimmed):

```text
My app/
├── nodegx.project.json        settings, design tokens, the link to a backend
├── components/
│   ├── _registry.json         the list of every component
│   ├── App/
│   ├── Components/PuppyCard/
│   │   ├── component.json     its name, path and type
│   │   ├── nodes.json         the nodes and their settings
│   │   └── connections.json   the wires between them
│   └── Pages/Landing/
├── docs/                      the brief and build plan from scoping
├── noodl_modules/             fonts and icon sets
├── CLAUDE.md                  a note for AI tools opened in this folder
└── .mcp.json                  connects Claude to this project
```

Every file is JSON (a plain text format for structured data) or Markdown. You can open any of them in a text editor.

## Components, nodes and wires

A **component** is a reusable piece of the app: a page, a card, a form. Each one is a folder with three files.

`nodes.json` lists the component's **nodes**. Each node has an id, a type, a label and its settings. Visual nodes also name their parent and children, which is how the screen's layout is stored. This is the text on a real puppy card (a few settings trimmed):

```json
{
  "id": "breedText",
  "type": "Text",
  "label": "Breed",
  "parameters": {
    "fontSize": "var(--text-sm)",
    "color": "var(--primary)"
  },
  "parent": "body-2"
}
```

`connections.json` holds the **wires**. Each wire runs from one node's output to another node's input:

```json
{
  "fromId": "cardInputs",
  "fromProperty": "breed",
  "toId": "breedText",
  "toProperty": "text"
}
```

Here `cardInputs` is the card's **Component Inputs** node: the list of values the card accepts. This wire sends the card's `breed` value into the Text node above.

## Why plain files suit AI and git

**Claude can read them.** A graph stored as text is something Claude reads the same way it reads code.

**Git can compare them.** A change shows up as a few changed lines. Swapping a colour on one card is one line in one `nodes.json`. See [GitHub basics](https://learn.nodegx.io/online/github-basics).

**You and Claude can both work on them.** NodeGX reads the files fresh from disk. If a file has changed since Claude last read it, because you saved in the editor for example, Claude's write is refused instead of overwriting your work. Claude then has to read it again. [Changing things yourself](https://learn.nodegx.io/build/your-changes) covers this.

Do not edit the JSON by hand. It skips the checks below, and a broken file often still loads, which makes the mistake hard to find later. `CLAUDE.md` tells AI tools the same thing.

## The brief and the build plan

When Claude creates a project, it first [scopes the app with you](https://learn.nodegx.io/plan/scoping). It then writes that conversation into `docs/`:

| File | What it holds |
|------|---------------|
| `docs/BRIEF.md` | What the app is, who uses it, and what it deliberately does not do |
| `docs/ARCHITECTURE.md` | The page map, the data model and the backend |
| `docs/CONVENTIONS.md` | Rules for how this app is built. Editing it changes what gets built |
| `docs/decisions/000-initial-scope.md` | The full record: what you asked for, what was decided, what was rejected, what is still open, the proposed build plan and the conversation itself |

The **build plan** has one step for each page you agreed. It is written down but not run. A new project holds only an empty App and Home page until you have reviewed the plan and asked Claude to build it.

## Every change is checked

Every write goes through **validation**: a check against NodeGX's file format and its rules about how nodes fit together. The check runs before any file is created. A rejected write leaves nothing on disk and comes back to Claude with an explanation and a suggested fix.

For a bigger job, Claude uses a **plan**. It adds each component to the plan, and nothing is written to disk until the plan is applied in one go.

## The style vocabulary

Nodes do not store raw colours or sizes. They store **design tokens**: named styles such as `--primary`, `--space-5` or `--radius-xl`, written in a node's settings as `var(--primary)`.

The project's own token values are kept in `nodegx.project.json`. Change one, and every node that uses it changes. The connector tells Claude to read the full list before it builds anything bigger than a small fix, so a new page matches the rest. [Describing how it should look](https://learn.nodegx.io/build/describing-a-look) shows how to use this.

## The local backend

An app with Record, User or Cloud Function nodes needs a **backend** (somewhere to save data and user accounts). Claude sets one up on your computer, starts it and links it to the project. It can create the collections (tables of records) the app needs at the same time.

The backend's data lives in NodeGX's own folder on your computer (`~/.noodl/backends`), not in the project folder. The project stores the link to it, in `nodegx.project.json` (trimmed):

```json
"cloudservices": {
  "endpoint": "http://localhost:8581",
  "type": "nodegx"
}
```

So your saved records do not go into git with the project. A live app needs a backend of its own: see [Putting your app online](https://learn.nodegx.io/online/putting-it-online).

## The render check

After Claude builds anything visual, it can **render** the project: run it without a window and take screenshots. It gets back measurements and the pictures, and looks at them to check its own work. A graph says what should appear. A render shows what does.

## The observe connector

The observe connector is a second connector that watches the app while it runs in NodeGX. You set it up from Editor Settings.

It lets Claude list the nodes in the running app, read a value on any of them, and click or type in the app. The main loop is: start a trace, reproduce the problem (Claude can click, or you can), then ask why a value on screen is empty. It works out from the graph and the trace where the data stopped.

Try it when something shows the wrong thing or nothing at all:

```text
The puppy list on the Landing page is empty. Use the observe connector to trace it and find where the data stops.
```

## Quick reference

- A project is a folder of plain files. Each component is a folder with `component.json`, `nodes.json` and `connections.json`.
- Nodes hold settings; wires run from one node's output to another's input.
- `docs/` holds the brief, the conventions and the build plan from scoping.
- Every write is validated first. A rejected write changes nothing.
- Styles are design tokens (`var(--primary)`), stored in `nodegx.project.json`.
- Backend data lives in `~/.noodl/backends`, outside the project folder.
- The render check and the observe connector let Claude see what the app really does.
