Universal HTTP Engine

Velocity HTTP.

The production-grade, zero-dependency HTTP client for modern applications. Built-in Sequential Polling, Retry Logic, and full TypeScript safety. Under 3KB gzipped.

Documentation
$npm install velocity-http
basics.ts
import Velocity from 'velocity-http';
const api = new Velocity({
baseURL: 'https://api.example.com'
});
// 1. Simple GET request
const users = await api.get('/users');
// 2. POST with data
await api.post('/users', { name: 'Kamlesh' });
hooks_explained.ts
// Run this before EVERY request (like adding a token)
api.onRequest((config) => {
return {
...config,
headers: { ...config.headers, Authorization: 'Bearer Secret-Key' }
};
});
// Run this after EVERY response (like checking for errors)
api.onResponse((res) => {
if (res.status === 401) console.log('Log in again!');
return res;
});

Test it in real-time.

Enter any API endpoint and see Velocity handle the request with precision. No more simulator—this is live.

Velocity Studio
Loading...
JSON Response

Awaiting network output

Terminal
3KB
Bundle Size
50k+
Monthly Installs
4.9/5
User Satisfaction
100%
Type Coverage

Everything you need. Nothing you don't.

A tiny core with powerful, well-tested features.

Sequential Safety

Built-in busy lock prevents overlapping polling requests automatically.

example.ts
// Only one poll at a time
if (this.isBusy) return;
this.isBusy = true;

Simple Hooks

One-liner hooks for auth, logging, or data transforms. No arrays, no complexity.

example.ts
api.onRequest((config) => ({
...config,
headers: { Auth: '...' }
}));

Smart Polling

Configurable intervals, maxAttempts, and validation for complex background tasks.

example.ts
poll: {
interval: 2000,
maxAttempts: 10,
validate: (d) => d.ready
}

Velocity vs Axios

Why developers are switching to a lighter alternative.

FeatureVelocity HTTPAxios
Bundle Size~3KB (Gzipped)~11KB (Gzipped)
DependenciesZero (Native Fetch)Several
Sequential PollingBuilt-inManual Implementation
Retry LogicNative SupportPlugins Required
TypeScriptFirst-classGood
Pro Integration

Built for React developers.

Velocity is designed to be the backbone of your data layer. Use our reactive useFetch pattern to handle loading, errors, and automatic request cancellation with zero boilerplate.

  • Automatic AbortController management
  • Reactive dependency tracking via JSON memoization
  • Built-in success/error callbacks
  • Type-safe HTTP method handling
useFetch.ts
import { useState, useEffect, useCallback, useRef, useMemo } from "react";
import Velocity, {
type VelocityConfig,
type VelocityResponse,
} from "velocity-http";
type VelocityMethod =
| ((url: string, config?: VelocityConfig) => Promise<VelocityResponse<any>>)
| ((url: string, data?: any, config?: VelocityConfig) => Promise<VelocityResponse<any>>);
interface FetchPayloadType<T, R> {
client: VelocityMethod;
url: string;
options?: VelocityConfig;
body?: T;
manual?: boolean;
dontCall?: boolean;
}
export const useFetch = <T = unknown, R = any>({
client,
url,
options,
body,
manual = false,
dontCall = false,
}: FetchPayloadType<T, R>) => {
const [data, setData] = useState<R | null>(null);
const [loading, setLoading] = useState<boolean>(!manual && !dontCall);
const [error, setError] = useState<string | null>(null);
const abortControllerRef = useRef<AbortController | null>(null);
const optionsKey = useMemo(() => JSON.stringify(options), [options]);
const bodyKey = useMemo(() => JSON.stringify(body), [body]);
const fetchData = useCallback(
async (overrides?: VelocityConfig) => {
if (abortControllerRef.current) abortControllerRef.current.abort();
const controller = new AbortController();
abortControllerRef.current = controller;
setLoading(true);
setError(null);
try {
const finalConfig = { ...options, ...overrides, signal: controller.signal };
let response;
if (body !== undefined) {
response = await (client as Function)(url, body, finalConfig);
} else {
response = await (client as Function)(url, finalConfig);
}
if (!controller.signal.aborted) {
const result = response?.data ?? null;
setData(result);
}
} catch (err: any) {
if (err.name !== "AbortError") {
const msg = err.message || "Something went wrong";
setError(msg);
}
} finally {
if (!controller.signal.aborted) setLoading(false);
}
},
[client, url, optionsKey, bodyKey]
);
useEffect(() => {
if (!manual && !dontCall) fetchData();
return () => abortControllerRef.current?.abort();
}, [fetchData, manual, dontCall]);
return { data, loading, error, refetch: fetchData };
};