# Introduction to dcupl

Your agent can write the app. It can't guess your data. dcupl gives coding agents the real model of your product data, JSON answers they can parse and a build step you approve. The same model runs in production, served via TypeScript SDK and REST API (RAPI), and via MCP where it is turned on.

## Three things your agent gets that it can't make up

Agents don't crash on bad data. They succeed on the wrong data. That is the failure dcupl removes:

- **The real model, not a guess.** The agent reads actual properties and types before it writes a filter (`dcupl app models get --model Product`). For dcupl's own formats, `dcupl schemas get ModelDefinition --example` does the same.
- **An answer it can parse.** With `--json`, the `app`, `validate`, `workflow`, `files` and `schemas` commands answer in structured JSON, errors included. The agent knows what happened instead of scraping console text.
- **Changes you approve.** Data changes are staged first. One `dcupl app build` applies them, when you say so.

Works with Claude Code, Cursor, Codex and Copilot. The CLI plus `--json` is all an agent needs; the [dcupl skill](/agentic/the-skill) for Claude Code adds command patterns and known pitfalls. See [Build with agents](/agentic).

## What dcupl is

Technically, dcupl is a TypeScript SDK, a CLI and the Console, all working on the same models and data:

```mermaid
flowchart TB
  subgraph sdk["SDK (free)"]
    MODELS[Models] --> ENGINE[Query Engine]
    DATA[Data] --> ENGINE
    ENGINE --> LISTS[Lists & Catalogs]
  end

  CLI["CLI (free)"]

  subgraph console["Console (optional)"]
    EDITOR[Model Editor] --> WORKFLOWS[Data Workflows]
    WORKFLOWS --> STORAGE[CDN Storage]
    STORAGE -.->|"fetch data"| DATA
  end

  CLI -->|"dcupl app"| ENGINE
  CLI -->|"files push / pull"| STORAGE
```

### TypeScript SDK (free)

The core `@dcupl/core` package runs in any JavaScript environment, in the browser or in Node.js. It provides:

- **Models** - Define your data structure (like a database schema)
- **Query engine** - Filter, sort, and search with a flexible query language
- **Lists and catalogs** - Create queryable views of your data with facets and aggregations

The SDK is free, on npm, and works without any backend.

### CLI (free)

The free `@dcupl/cli` is the agent's way in, and yours: `dcupl init` scaffolds a project, `dcupl serve` serves its files locally, `dcupl validate` checks the models, `dcupl app` queries the data from your terminal, and `dcupl files push` / `dcupl files pull` sync the files with the Console. With `--json`, the `app`, `validate`, `workflow`, `files` and `schemas` commands answer in JSON. See [How the CLI works](/cli/how-it-works).

### Console (optional)

The [dcupl Console](/console) is a web platform that adds:

- **Visual model editor** - Design data models with a UI
- **Data workflows** - Load, join and clean exports (PIM dumps, ERP prices, file drops on Azure Blob or S3), run them on a dev runner first, then go to production
- **REST API deployment** - Run dcupl queries server-side when needed; a deployed instance can be an MCP server where it is turned on

Files and versions, the data explorer and team roles are on the [Console overview](/console).

You can use the SDK alone for simpler projects, or add the Console for data pipelines and APIs.

## Where to start

Pick the path that matches how you work:

- **You write the app in TypeScript.** Start with the [SDK quick start](/sdk/quick-start): models, data and a filtered list in a few minutes.
- **You manage data in the Console.** Start with your [first Console project](/console/getting-started): import a file, check the model, run the application.
- **Your agent does the work.** Start with the [agent setup](/agentic/setup): install the CLI, give the agent the skill and let it drive `dcupl` with `--json`.

Whichever path you take, the [CLI](/cli) scaffolds, serves, validates, queries and syncs the same project files.

## Queries without a backend

This is the frontend-first part of dcupl. A product catalog, data table or search interface usually needs a backend round-trip for every filter change. dcupl loads the data once and runs every query locally:

```mermaid
flowchart LR
  subgraph traditional["Traditional approach"]
    direction TB
    FE[Frontend] -->|"filter request"| API[Backend API]
    API -->|"SQL query"| DB[(Database)]
    DB -->|"results"| API
    API -->|"JSON"| FE
  end
  subgraph dcupl["dcupl approach"]
    direction TB
    DATA[Data Source] -->|"load once"| SDK["dcupl SDK\n(in browser)"]
    SDK -->|"instant queries"| UI[Your UI]
  end
```

That removes three costs of the round-trip:

- **Network latency** - Users wait for a network round-trip on every interaction
- **Server costs** - Every user action requires server compute
- **Backend dependencies** - Frontend teams wait for API endpoints

Because you load the actual data from the start (spreadsheets, CSV or JSON files, or files managed in the Console), a prototype built with dcupl reflects reality instead of breaking when the real data arrives.

## When should you use dcupl?

dcupl works well for applications where users explore and filter data:

| Use Case                | Example                      | Why dcupl Helps                              |
| ----------------------- | ---------------------------- | -------------------------------------------- |
| **Product catalogs**    | E-commerce, marketplaces     | Fast faceted search with instant filtering   |
| **Data dashboards**     | Analytics, admin panels      | Client-side aggregations without server load |
| **Search interfaces**   | Document search, directories | Instant results as users type                |
| **Configuration tools** | Product configurators        | Complex dependent filters                    |

### When to consider alternatives

dcupl is not the right choice for every project:

- **Real-time collaboration** - If multiple users edit the same data simultaneously, use a real-time database like Firebase or Supabase
- **Constantly changing data** - dcupl is optimized for read-heavy workloads
- **Sensitive data** - Any data you ship to the browser is inspectable by the user. Keep secrets, personal data, and records users shouldn't see on the server and only send what the current user is allowed to query
- **Very large datasets in the browser** - Data that is too large to download to every client doesn't belong there. Run it on a server-hosted dcupl instance exposed as a [REST API](/console/rapi), or use a dedicated search service

## What dcupl is not

| Not this                    | Explanation                                                                                                                                                             |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Not a database**          | dcupl doesn't replace PostgreSQL or MongoDB. It loads data into memory for fast querying. You can store files on the dcupl CDN, but it is not a transactional database. |
| **Not a CMS**               | dcupl doesn't manage content creation or editorial workflows. Use it alongside a CMS if needed.                                                                         |
| **Not a backend framework** | dcupl reduces backend dependencies; it doesn't replace your entire backend.                                                                                             |
| **Not a search service**    | Search services like Algolia run server-side and charge per query, with typo tolerance and relevance ranking. dcupl queries locally and has neither.                    |

For a detailed comparison, see [dcupl vs alternatives](/learn/concepts/dcupl-vs-alternatives).

## Data size and limits

Measured with 1 million items: indexed queries took 25–65 ms, facets about 2.7 s. Query time grows with the number of items, and what fits depends on your models, your data and the device, because the SDK keeps all data in memory:

| Environment | Constraint                                                                                                  | What to do                                                        |
| ----------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| **Browser** | Browser memory (varies by device)                                                                           | Load only the data the app needs, or query a REST API instance    |
| **Node.js** | Node.js heap memory (default depends on system memory, often ~2–4 GB; raise it with `--max-old-space-size`) | Increase the heap size, or run the queries on a REST API instance |
| **Any**     | A model holds at most about 16.7 million items (V8's `Map` size limit)                                      | Split the data across models or reduce it                         |

To work with large datasets:

- Structure data efficiently (normalize with references, avoid duplication)
- Load only what's needed: select resources with tags, or drop rows with a parsed-file transformer in the loader
- Run heavy queries on a [REST API instance](/console/rapi) and send the results to the client, or combine both: heavy queries on the server, instant filtering of the result on the client

## Where dcupl runs

| Environment                       | Use Case                                                      |
| --------------------------------- | ------------------------------------------------------------- |
| **Browser**                       | Interactive UIs, instant filtering, works offline once loaded |
| **Node.js**                       | SSR, build-time data processing, scripts                      |
| **REST API instance on a runner** | Server-side API for non-browser clients, heavy queries        |

Same SDK, same query API, with any JavaScript framework (React, Vue, Angular, Svelte or none). With SSR, the first page load carries real data; the browser then loads the same data into its own dcupl instance and takes over the interactions.

## Who uses dcupl?

**Developers who build with an agent** point the agent at an export and get a typed model and a working app on real data. The agent does the keystrokes; you see what it did, what is pending and what passed, and you approve the build. See the [CLI quickstart](/cli) and [Build with agents](/agentic).

**Agencies that deliver data-heavy apps for clients** reuse models and workflows across projects and keep agent changes reviewable. Models, workflows and quality rules are JSON files in the repository; workflows run on a dev runner before they reach the client, and the Console canvas edits the same files the agent writes. See [Workflows](/console/workflows).

**Companies that run the app and own the data** get clean, typed product data for their apps and their own AI agents. The runtime can run on their own infrastructure, and a deployed REST API instance can be an MCP server where it is turned on. See [REST APIs](/console/rapi) and the [MCP endpoint](/console/rapi/mcp).

## Key concepts

Here are the terms you'll see throughout the docs:

**Model** - A definition of your data structure. Similar to a database table schema or TypeScript interface.

**Property** - A field in a model (name, price, category). Properties have types like `string`, `int`, `float`, `boolean`, or `date`.

**List** - A queryable view of model data. You create lists, add filter conditions, and retrieve results.

**Catalog** - The query interface on a list. Use it to filter, sort, get facet counts, and run aggregations.

**Facets** - Counts of items per value, used for filter UIs (e.g., "Electronics (24), Furniture (12)").

**Reference** - A property that points to items of another model, single- or multi-valued (a product's `category`). References let you query across models, e.g. on `category.name`.

**init / update** - Data and model changes are staged until you apply them: `await dcupl.init()` once, then `await dcupl.update()` after later changes. Both resolve to `false` when they fail instead of throwing, so check the result.

## A simple example

Here is a complete example that loads products and filters them:

```typescript filename="example.ts"
import { Dcupl } from '@dcupl/core';

const dcupl = new Dcupl();

// 1. Define the data structure
dcupl.models.set({
  key: 'Product',
  properties: [
    { key: 'name', type: 'string' },
    { key: 'price', type: 'int' },
    { key: 'category', type: 'string' },
  ],
});

// 2. Load data (can come from an API, file, or inline)
dcupl.data.set(
  [
    { key: 'p1', name: 'Laptop', price: 999, category: 'Electronics' },
    { key: 'p2', name: 'Mouse', price: 29, category: 'Electronics' },
    { key: 'p3', name: 'Desk', price: 299, category: 'Furniture' },
    { key: 'p4', name: 'Chair', price: 199, category: 'Furniture' },
  ],
  { model: 'Product' },
);

// 3. Initialize (builds indexes for fast queries)
await dcupl.init();

// 4. Create a list and filter
const list = dcupl.lists.create({ modelKey: 'Product' });
list.catalog.query.addCondition({
  attribute: 'category',
  operator: 'eq',
  value: 'Electronics',
});

// 5. Get results
console.log(list.catalog.query.items());
// [{ key: 'p1', name: 'Laptop', ... }, { key: 'p2', name: 'Mouse', ... }]

// 6. Get facet counts for a filter UI
console.log(list.catalog.fn.facets({ attribute: 'category' }));
// [{ value: 'Electronics', size: 2, selected: true, ... },
//  { value: 'Furniture', size: 2, selected: false, ... }]
```

To build and run this step by step, continue with the [Quick start](/sdk/quick-start).

## Next steps

- [Quick start](/sdk/quick-start) — Build your first dcupl application in 5 minutes
- [CLI](/cli) — Scaffold a project, run it locally, sync it with the Console
- [Build with agents](/agentic) — Let an AI agent drive the CLI
- [Console](/console) — Manage models, workflows and REST APIs without code
- [Core concepts](/sdk/core-concepts) — Understand models, lists, and queries
- [Architecture](/learn/concepts/architecture) — How SDK, CLI and Console work together
- [React Integration](/learn/tutorials/react-integration) — Use dcupl in a React app
- [Vue Integration](/learn/tutorials/vue-integration) — Use dcupl in a Vue app
