Comparison

How Caller compares to Axios, ky, ofetch, and native fetch. Understand the trade-offs and choose the right HTTP client for your project.

Overview

The JavaScript ecosystem has many excellent HTTP clients. This page provides an honest comparison between Caller and popular alternatives, helping you understand when Caller is the right choice and when you might prefer something else.

We believe in picking the right tool for the job. Caller excels at type-safe, schema-validated API consumption in TypeScript projects—but it's not always the best choice for every scenario.


Quick Comparison

FeatureCallerAxioskyofetchfetch
Type Safety✅ Full inference⚠️ Manual⚠️ Manual⚠️ Manual❌ None
Schema Validation✅ Built-in
Fluent API⚠️ Partial
Retries✅ Built-in❌ Plugin✅ Built-in✅ Built-in
Caching✅ Built-in
React Hooks✅ Built-in
Interceptors
Bundle Size~8kb~13kb~4kb~5kb0kb
Node.js Support✅ 18+
Browser SupportModernAllModernModernModern

Detailed Comparisons


Feature Deep Dive

Type Safety

The biggest differentiator between Caller and alternatives is the type system. Most HTTP clients require you to manually define interfaces and hope they match your API:

Traditional Approach
// You define this manually
interface User {
  id: string;
  name: string;
  email: string;
}

// API changes "email" to "emailAddress"
// TypeScript doesn't know - runtime error!
const user = await axios.get<User>('/users/123');
console.log(user.data.email); // undefined at runtime

With Caller, your schema is the source of truth:

Caller Approach
// Schema is the source of truth
const schemas = IgniterCallerSchema.create()
  .path('/users/:id', (path) =>
    path.get({
      responses: {
        200: z.object({
          id: z.string(),
          name: z.string(),
          emailAddress: z.string(), // API changed this
        }),
      },
    })
  )
  .build();

const { data } = await api.get('/users/:id').execute();
console.log(data.emailAddress); // TypeScript knows the correct field

React Integration

Caller provides first-class React hooks, while other libraries require external wrappers like TanStack Query:

Caller React Hooks
import { useCaller } from '@igniter-js/caller/client';

function UserProfile({ id }: { id: string }) {
  const api = useCaller('main');
  
  const { data, isLoading } = api.get('/users/:id')
    .params({ id })
    .useQuery({ staleTime: 10_000 });
  
  return <div>{data?.name}</div>;
}
Axios + TanStack Query
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';

function UserProfile({ id }: { id: string }) {
  const { data, isLoading } = useQuery({
    queryKey: ['user', id],
    queryFn: () => axios.get(`/users/${id}`).then(r => r.data),
  });
  
  return <div>{data?.name}</div>;
}

Migration Guides


Summary

ScenarioRecommendation
New TypeScript project with APIsCaller
Existing Axios codebase, no time to migrateAxios
Ultra-minimal bundle, simple needsky or fetch
Nuxt.js applicationofetch
IE11 support requiredAxios
Type-safe, validated API layerCaller

Choose Caller when type safety, developer experience, and production-readiness matter. Choose alternatives when simplicity or specific compatibility requirements take priority.


Next Steps