npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

hono-query-client

v1.0.10

Published

A type-safe, React Query-powered client library for Hono applications with automatic hook generation and intelligent cache management

Readme

hono-query-client

A type-safe, React Query-powered client library for Hono applications. Automatically generates React hooks for your Hono API routes with full TypeScript support, intelligent cache management, and method-specific mutations.

Features

  • 🔥 Type-Safe: Full TypeScript support with automatic type inference from your Hono app
  • Method-Specific Mutations: Dedicated hooks for POST, PUT, PATCH, and DELETE operations
  • 🔄 Intelligent Cache Management: Automatic cache invalidation based on endpoint patterns
  • 📦 Zero Configuration: Works out of the box with your existing Hono setup
  • 🎯 Optimistic Updates: Built-in support for optimistic mutations
  • 🌊 Infinite Queries: Native support for paginated data with infinite scrolling
  • 🛡️ Error Handling: Comprehensive error handling with structured error responses
  • 🎣 React Query Integration: Built on top of TanStack React Query for robust state management

Installation

npm install hono-query-client hono @tanstack/react-query
# or
yarn add hono-query-client hono @tanstack/react-query
# or
pnpm add hono-query-client hono @tanstack/react-query
# or
bun add hono-query-client hono @tanstack/react-query

Note: @tanstack/react-query is a peer dependency and must be installed. The library provides a default QueryClient instance, so you don't need to manually configure it unless you want custom settings.

Quick Start

1. Create API Client and Provider

// lib/api.ts
import { hc } from 'hono/client';
import { createHonoQueryProxy, HonoQueryProvider } from 'hono-query-client';
import type { AppType } from './server'; // Your Hono app type

const honoClient = hc<AppType>('http://localhost:3000');
export const api = createHonoQueryProxy(honoClient);

// Export the provider with the client pre-configured
export const AppProvider = ({ children }: { children: React.ReactNode }) => (
  <HonoQueryProvider client={honoClient}>
    {children}
  </HonoQueryProvider>
);

Note: The HonoQueryProvider automatically creates a default QueryClient and includes the TanStack Query QueryClientProvider, so you don't need to manually create a query client or wrap your app with both providers.

Optional: You can still provide your own QueryClient if you need custom configuration:

import { QueryClient } from '@tanstack/react-query';

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 5 * 60 * 1000, // 5 minutes
    },
  },
});

export const AppProvider = ({ children }: { children: React.ReactNode }) => (
  <HonoQueryProvider queryClient={queryClient} client={honoClient}>
    {children}
  </HonoQueryProvider>
);

2. Set up your App

// App.tsx
import { AppProvider } from './lib/api';

function App() {
  return (
    <AppProvider>
      <YourApp />
    </AppProvider>
  );
}

3. Use in Components

import { api } from './lib/api';

function UserProfile({ userId }: { userId: string }) {
  // Query data
  const { data: user, isLoading, error } = api.users[':id'].useQuery(
    { param: { id: userId } },
    { enabled: !!userId }
  );

  // Method-specific mutations
  const updateUser = api.users[':id'].patch.useMutation({
    onSuccess: () => {
      console.log('User updated successfully!');
    }
  });

  const deleteUser = api.users[':id'].delete.useMutation();

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <h1>{user?.name}</h1>
      <button 
        onClick={() => updateUser.mutate({ 
          param: { id: userId }, 
          json: { name: 'New Name' } 
        })}
      >
        Update User
      </button>
      <button onClick={() => deleteUser.mutate({ param: { id: userId } })}>
        Delete User
      </button>
    </div>
  );
}

Core Concepts

Query Hooks

Query hooks are automatically generated for any endpoint that supports GET requests:

// Basic query
const { data, isLoading, error } = api.users.useQuery();

// Query with parameters
const { data: user } = api.users[':id'].useQuery({ 
  param: { id: '123' } 
});

// Query with query parameters
const { data: posts } = api.posts.useQuery({ 
  query: { page: 1, limit: 10 } 
});

Method-Specific Mutations

Instead of a generic useMutation, hono-query provides method-specific hooks that automatically handle the correct HTTP method:

// POST - Create new resource
const createPost = api.posts.post.useMutation();
createPost.mutate({ json: { title: 'New Post', content: '...' } });

// PATCH - Update existing resource
const updatePost = api.posts[':id'].patch.useMutation();
updatePost.mutate({ 
  param: { id: '123' }, 
  json: { title: 'Updated Title' } 
});

// DELETE - Remove resource
const deletePost = api.posts[':id'].delete.useMutation();
deletePost.mutate({ param: { id: '123' } });

// PUT - Replace resource
const replacePost = api.posts[':id'].put.useMutation();
replacePost.mutate({ 
  param: { id: '123' }, 
  json: { title: 'New Title', content: 'New Content' } 
});

Infinite Queries

For paginated data with infinite scrolling:

const {
  data,
  fetchNextPage,
  hasNextPage,
  isFetchingNextPage,
} = api.posts.useInfiniteQuery(
  { query: { limit: 10 } },
  {
    getNextPageParam: (lastPage) => lastPage.nextCursor,
  }
);

Error Handling

The library provides structured error handling:

import { HonoQueryError } from 'hono-query-client';

const mutation = api.users.post.useMutation({
  onError: (error) => {
    if (error instanceof HonoQueryError) {
      console.log('Status:', error.response.status);
      console.log('Error data:', error.data);
    }
  }
});

Cache Management

Automatic cache invalidation happens based on endpoint patterns:

  • Collection mutations (POST /users) invalidate the collection cache (/users)
  • Resource mutations (PATCH /users/:id) invalidate both the resource (/users/:id) and collection (/users)

You can also manually manage cache:

import { useHonoQueryContext } from 'hono-query-client';

function MyComponent() {
  const { utils } = useHonoQueryContext();
  
  // Manual cache invalidation
  const handleRefresh = () => {
    utils.users.invalidate();
  };
}

Advanced Usage

Type Inference

The library automatically infers types from your Hono app:

import type { AppType } from './server';

// All these types are automatically inferred
type UserResponse = ApiOutputs<AppType>['users'][':id']; // GET response
type UserInput = ApiInputs<AppType>['users'][':id']; // GET input
type CreateUserInput = ApiMutationInputs<AppType>['users']; // POST input
type CreateUserOutput = ApiMutationOutputs<AppType>['users']; // POST output

Custom Headers and Configuration

const honoClient = hc<AppType>('http://localhost:3000', {
  headers: {
    'Authorization': 'Bearer token',
    'X-Custom-Header': 'value'
  },
  // Add dynamic headers
  headers: () => ({
    'Authorization': `Bearer ${localStorage.getItem('token')}`,
  })
});

Optimistic Updates

const updateUser = api.users[':id'].patch.useMutation({
  onMutate: async (variables) => {
    // Cancel outgoing refetches
    await queryClient.cancelQueries({ queryKey: ['users', variables.param.id] });
    
    // Snapshot previous value
    const previousUser = queryClient.getQueryData(['users', variables.param.id]);
    
    // Optimistically update
    queryClient.setQueryData(['users', variables.param.id], {
      ...previousUser,
      ...variables.json
    });
    
    return { previousUser };
  },
  onError: (err, variables, context) => {
    // Rollback on error
    queryClient.setQueryData(
      ['users', variables.param.id], 
      context?.previousUser
    );
  },
});

API Reference

Core Functions

  • createHonoQueryProxy<TApp>(client) - Creates the main API proxy
  • HonoQueryProvider - React context provider for the query client
  • useHonoQueryContext() - Hook to access query client and utils

Generated Hook Patterns

  • api.endpoint.useQuery(input?, options?) - Query hook for GET requests
  • api.endpoint.useInfiniteQuery(input, options) - Infinite query hook
  • api.endpoint.post.useMutation(options?) - POST mutation hook
  • api.endpoint.put.useMutation(options?) - PUT mutation hook
  • api.endpoint.patch.useMutation(options?) - PATCH mutation hook
  • api.endpoint.delete.useMutation(options?) - DELETE mutation hook

Type Exports

  • HonoClient<TApp> - The raw Hono client type
  • ClientQueryOutput<TApp, ...> - GET response types
  • ClientQueryInput<TApp, ...> - GET input types
  • ClientMutationOutput<TApp, ...> - Mutation response types
  • ClientMutationInput<TApp, ...> - Mutation input types
  • GetQueryOutput<TClient, ...> - Advanced GET response type
  • GetQueryInput<TClient, ...> - Advanced GET input type
  • GetMutationOutput<TClient, ...> - Advanced mutation response type
  • GetMutationInput<TClient, ...> - Advanced mutation input type
  • HonoQueryError - Error class for failed requests

For a much better developer experience, see the Advanced Type-Safety Patterns guide to avoid passing TApp in every type.

Examples

See the examples directory for complete working examples:

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see the LICENSE file for details.