@data-client/vue

Async State Management without the Management. REST, GraphQL, SSE, Websockets, Fetch
24,950 2,039
Install
npm install @data-client/vue
Latest Version:0.18.2
Vue:3
License:Apache-2.0
Last Updated:Oct 25, 2026
Links: GitHub  ·  npm
Maintainer: ntucker
Reactive Data Client

The scalable way to build applications with dynamic data.

Declarative resource definitions for REST, GraphQL, Websockets+SSE and more
Performant rendering in React, NextJS, React Native, Expo, Vue

Schema driven. Zero updater functions.

CircleCI Coverage Status Percentage of issues still open bundle size npm version PRs Welcome Agent Skills Chat

📖Read The Docs  |  🏁Getting Started  |  🤖Agent Skills
🎮 Demos:   Todo  |  Github Social  |  NextJS SSR  |  Websockets+SSR

Installation

npm install --save @data-client/react @data-client/rest @data-client/test

To have Claude Code, Cursor or Codex load the skills these packages ship for their version, link them into .agents/skills (.claude/skills links to it) and commit the links:

npx --no data-client-skills

For more details, see the Getting Started docs page.

Let your coding agent set it up

Or skip the install above and tell your coding agent:

Set up `@data-client/react` and use it for all API data. Install its setup skill first: `npx skills add reactive/data-client --skill data-client-setup -y`, then follow it.

It installs the packages, wires up the provider and links the skills they ship.

Usage

Simple TypeScript definition

class User extends Entity {
  id = '';
  username = '';
}

class Article extends Entity {
  id = '';
  title = '';
  body = '';
  author = User.fromJS();
  createdAt = Temporal.Instant.fromEpochMilliseconds(0);

  static schema = {
    author: User,
    createdAt: Temporal.Instant.from,
  };
}

Create collection of API Endpoints

const UserResource = resource({
  path: '/users/:id',
  schema: User,
  optimistic: true,
});

const ArticleResource = resource({
  path: '/articles/:id',
  schema: Article,
  searchParams: {} as { author?: string },
  optimistic: true,
  paginationField: 'cursor',
});

One line data binding

const article = useSuspense(ArticleResource.get, { id });
return (
  <article>
    <h2>
      {article.title} by {article.author.username}
    </h2>
    <p>{article.body}</p>
  </article>
);

Reactive Mutations

const ctrl = useController();
return (
  <>
    <CreateArticleForm
      onSubmit={article =>
        ctrl.fetch(ArticleResource.getList.push, article)
      }
    />
    <ProfileForm
      onSubmit={user =>
        ctrl.fetch(UserResource.update, { id: article.author.id }, user)
      }
    />
    <button onClick={() => ctrl.fetch(ArticleResource.delete, { id })}>
      Delete
    </button>
  </>
);

Subscriptions

const price = useLive(PriceResource.get, { symbol });
return price.value;

Type-safe Imperative Actions

const ctrl = useController();
await ctrl.fetch(ArticleResource.update, { id }, articleData);
await ctrl.fetchIfStale(ArticleResource.get, { id });
ctrl.expireAll(ArticleResource.getList);
ctrl.invalidate(ArticleResource.get, { id });
ctrl.invalidateAll(ArticleResource.getList);
ctrl.setResponse(ArticleResource.get, { id }, articleData);
ctrl.set(Article, { id }, articleData);

Programmatic queries

const queryTotalVotes = new Query(
  new Collection([BlogPost]),
  posts => posts.reduce((total, post) => total + post.votes, 0),
);

const totalVotes = useQuery(queryTotalVotes);
const totalVotesForUser = useQuery(queryTotalVotes, { userId });
const groupTodoByUser = new Query(
  TodoResource.getList.schema,
  todos => Object.groupBy(todos, todo => todo.userId),
);
const todosByUser = useQuery(groupTodoByUser);

Powerful Middlewares

class LoggingManager implements Manager {
  middleware: Middleware = controller => next => async action => {
    console.log('before', action, controller.getState());
    await next(action);
    console.log('after', action, controller.getState());
  };

  cleanup() {}
}
class TickerStream implements Manager {
  middleware: Middleware = controller => {
    this.handleMsg = msg => {
      controller.set(Ticker, { id: msg.id }, msg);
    };
    return next => action => next(action);
  };

  init() {
    this.websocket = new WebSocket('wss://ws-feed.myexchange.com');
    this.websocket.onmessage = event => {
      const msg = JSON.parse(event.data);
      this.handleMsg(msg);
    };
  }
  cleanup() {
    this.websocket.close();
  }
}

Integrated data mocking

const fixtures = [
  {
    endpoint: ArticleResource.getList,
    args: [{ maxResults: 10 }] as const,
    response: [
      {
        id: '5',
        title: 'first post',
        body: 'have a merry christmas',
        author: { id: '10', username: 'bob' },
        createdAt: new Date(0).toISOString(),
      },
      {
        id: '532',
        title: 'second post',
        body: 'never again',
        author: { id: '10', username: 'bob' },
        createdAt: new Date(0).toISOString(),
      },
    ],
  },
  {
    endpoint: ArticleResource.update,
    response: ({ id }, body) => ({
      ...body,
      id,
    }),
  },
];

const Story = () => (
  <MockResolver fixtures={options[result]}>
    <ArticleList maxResults={10} />
  </MockResolver>
);

...all typed ...fast ...and consistent

For the small price of 9kb gzipped.    🏁Get started now

Features

Examples

  • Todo: GitHub | Sandbox | Edit on CodeSandbox
  • Github: GitHub | Sandbox
  • NextJS: GitHub | Sandbox | Edit on CodeSandbox
  • Websockets: GitHub | Sandbox | Website

API

Reactive Applications

Define Data

Networking definition
Data model
Data Type Mutable Schema Description Queryable
Object ✅ Entity, EntityMixin single unique object ✅
✅ Union(Entity) polymorphic objects (A | B) ✅
🛑 Object statically known keys 🛑
Invalidate(Entity) delete an entity 🛑
List ✅ Collection(Array) growable lists ✅
🛑 Array immutable lists 🛑
All list of all entities of a kind ✅
Map ✅ Collection(Values) growable maps ✅
🛑 Values immutable maps 🛑
Scalar ✅ Scalar lens-dependent entity fields ✅
any Query(Queryable) memoized custom transforms ✅
Lazy(Schema) deferred denormalization ✅

Related Packages

nuxt-open-fetch

Generate zero-overhead, 100% typed OpenAPI clients for Nuxt.

379,588 259
lumenql

Zero-dependency, typed GraphQL client with caching, request deduplication, retri...

245 4
rest-pipeline-js

Orchestrate REST API calls in sequential and parallel pipelines with retry, cach...

7,116 0
vue-data-fetcher

Vue Data Fetcher is a collection of composable functions that provide utility fu...

1,110
dbaas

Database as a service. Expose db to REST and GraphQL.

649

Version History

Version Released Vue License
0.18.2 ^3.4.0 Apache-2.0
0.18.1 ^3.0.0 Apache-2.0
0.18.0 ^3.0.0 Apache-2.0
0.16.1 ^3.0.0 Apache-2.0
0.16.0 ^3.0.0 Apache-2.0
Pre-releases (9)
Version Released Vue License
0.3.2-beta-20251201012906-ff2853c5a0da93a503b2b606c8fc724625b79308 ^3.0.0 Apache-2.0
0.3.2-beta-20251116224907-3174fe59b114d2037762a6458f5576d23e483ba4 ^3.0.0 Apache-2.0
0.2.0-beta-20251026233651-4c1d5c9084df801287cc120cd7a9c77b9bbe96e0 ^3.0.0 Apache-2.0
0.2.0-beta-20251026024409-a1c466cfd7aac770879b584acaac40fa61d01b61 ^3.0.0 Apache-2.0
0.2.0-beta-20251023121500-abcdefg ^3.0.0 Apache-2.0