Β· English Β· Korean
Fynk is an ultra-high-performance reactive HTTP client featuring automatic request deduplication, integrated caching, optimistic updates, and SSE live patch.
It delivers 1,700x faster performance than traditional HTTP clients while maintaining perfect data consistency.
- β‘ Performance First: intelligent cache-scheduler integration for dedupe and warm-cache reads
- π Zero Config Dedup: Automatic request deduplication prevents redundant network calls
- π― Framework Agnostic: Works seamlessly with React 19 and Vue 3
- π¦ Tiny Bundle: Minimal footprint with maximum performance
npm i fynk
# or
yarn add fynk
# or
pnpm add fynkimport { createClient, fetchAdapter } from "fynk";
// Create high-performance client
const client = createClient({
adapter: fetchAdapter("https://api.example.com"),
});
// Define your data models for normalized caching
type User = { id: number; name: string; email: string };
const UserModel = client.defineModel<User>({
key: "user",
id: (u) => u.id,
});// These 3 concurrent calls automatically become 1 network request!
const [user1, user2, user3] = await Promise.all([
client.get<User>("/users/1"), // β Network call
client.get<User>("/users/1"), // β Waits for above
client.get<User>("/users/1"), // β Waits for above
]);
// Result: All 3 get the same data, but only 1 HTTP request! β‘import { useQuery, useMutation } from "fynk/react";
function UserProfile({ userId }: { userId: number }) {
// Automatic deduplication + caching
const { data, pending, error, refetch } = useQuery<User>(client, {
key: ["user", userId],
request: () => client.get<User>(`/users/${userId}`),
model: UserModel, // Enables normalized caching
});
// Optimistic updates for instant UX
const { mutate } = useMutation<{ name: string }, User>(client, {
request: (vars) => client.post<User>("/users", { body: vars }),
optimistic: (draft, vars) => {
// UI updates instantly, rolls back if request fails
draft.insert(UserModel, { id: -1, name: vars.name, email: "" });
},
});
if (pending) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<h1>{data?.name}</h1>
<button onClick={() => mutate({ name: "New Name" })}>Update Name</button>
</div>
);
}<script setup lang="ts">
import { useQuery, useMutation } from "fynk/vue";
const { data, pending, error, refetch } = useQuery<User>(client, {
key: ["user", 1],
request: () => client.get<User>("/users/1"),
model: UserModel,
});
const { mutate, pending: saving } = useMutation(client, {
request: (vars) => client.post("/users", { body: vars }),
optimistic: (draft, vars) => draft.insert(UserModel, vars),
});
</script>
<template>
<div v-if="pending">Loading...</div>
<div v-else-if="error">Error occurred</div>
<div v-else>
<h1>{{ data?.name }}</h1>
<button @click="mutate({ name: 'Updated' })" :disabled="saving">
Update
</button>
</div>
</template>Fynk should be benchmarked by the behavior it adds on top of HTTP: request deduplication, warm cache reads, and query-level reuse.
| Scenario | What it measures |
|---|---|
native fetch, axios, alova |
Raw 10 concurrent identical GET requests |
ky, got |
Optional rows; install those packages to include them |
fynk (dedup) |
10 identical concurrent GETs collapsed by Fynk |
fynk runQuery |
Query helper dedupe with model normalization |
fynk (cached) |
Warm scheduler cache latency |
Benchmark: local API server, 10 concurrent identical requests to the same endpoint.
npm run bench # Run performance comparison- β‘ Cache-Scheduler β Integrated scheduler with sync cache lookup
- π Auto Request Deduplication β Concurrent requests automatically collapse into one
- π‘οΈ HTTP Basics Included β Params, timeout, abort signals, retry, and typed errors
- π― Smart Caching β Entity-based normalized cache prevents data duplication
- π§© Framework Bridges β Identical API for
fynk/reactandfynk/vue - π¨ Optimistic Updates β Built-in draft API for instant UX with rollback
- π Axios-Style Interceptors β Familiar request/response chain with hooks
- π‘ Live Sync (SSE) β Real-time updates via Server-Sent Events
Fynk is designed to reduce redundant work in app data flows through:
- Integrated Cache-Scheduler: Sync cache checks eliminate async overhead
- Smart Deduplication: Automatically prevents redundant requests
- Normalized Cache: Entity relations can be normalized and resolved later
// Just works - no setup needed for deduplication & caching
const { data, pending, error } = useQuery(client, {
key: ["user", userId],
request: () => client.get(`/users/${userId}`),
});
// Multiple components requesting same data? Only 1 network call! β‘| Feature | React | Vue | Vanilla |
|---|---|---|---|
| useQuery Hook | β
fynk/react |
β
fynk/vue |
β Core API |
| Auto Deduplication | β | β | β |
| Normalized Cache | β | β | β |
| Optimistic Updates | β | β | β |
These libraries can be compared with Fynk's core HTTP client API. got is Node-only, so it belongs in server/CLI benchmarks rather than browser or hook comparisons.
| Capability | Fynk | native fetch | ky | Axios | got | Alova |
|---|---|---|---|---|---|---|
| Runtime | Browser + Node | Browser + Node | Browser + Node | Browser + Node | Node only | Browser + Node |
| Params helper | Built-in | Manual | Built-in | Built-in | Built-in | Built-in |
| Timeout / abort | Built-in | Manual | Built-in | Built-in | Built-in | Built-in |
| Retry | Built-in | Manual | Built-in | Plugin/manual | Built-in | Strategy-based |
| 4xx/5xx error model | FynkError |
Manual | Built-in | Built-in | Built-in | Configurable |
| Interceptors / hooks | Built-in | Manual | Hooks | Interceptors | Hooks | Middleware/hooks |
| Request dedupe | Built-in | Manual | Manual | Manual | Manual | Strategy-based |
| Normalized cache | Built-in | None | None | None | None | No entity-normalized cache |
| React/Vue hooks | Built-in | None | None | None | None | Built-in |
React Query and TanStack Query are not HTTP clients. They are query/cache layers that call another client such as fetch, ky, or axios.
| Capability | Fynk | Alova | React Query | TanStack Query |
|---|---|---|---|---|
| Ships HTTP client | Yes | Yes | No | No |
| Query hook | React + Vue | Multi-framework | React | Multi-framework |
| Mutation hook | React + Vue | Multi-framework | React | Multi-framework |
| Infinite query | React + Vue | Supported patterns | Built-in | Built-in |
| Request dedupe | Built-in | Strategy-based | Query-key based | Query-key based |
| Normalized entity cache | Built-in | No | No | No |
| Optimistic update | Draft API | Supported | Supported | Supported |
| Persistence | Built-in cache snapshot | Supported | Plugin/persister | Plugin/persister |
Fynk is designed for modern apps that demand both blazing performance and effortless data consistency.
// Automatically sync cache with server-sent events
import { createEventSync } from "fynk";
const events = createEventSync("/events");
const off = events.on("user:updated", (userData) => {
client.normalize(UserModel, userData);
});
off();
events.close();const user = await client.get<User>("/users", {
params: { page: 1, tags: ["admin", "active"] },
timeout: 5_000,
retry: { attempts: 2, delay: 100 },
dedupe: true,
});const User = client.defineModel<User>({ key: "user", id: user => user.id });
const Post = client.defineModel<Post>({
key: "post",
id: post => post.id,
relations: { author: "user" },
});
client.normalize(Post, {
id: 1,
title: "Hello",
author: { id: 10, name: "Ada" },
});
const post = client.resolve(Post, 1);
await client.persist(localStorage);
await client.hydrate(localStorage);import { useInfiniteQuery } from "fynk/react";
const users = useInfiniteQuery(client, {
key: ["users"],
initialPageParam: 1,
request: page => client.get(`/users`, { params: { page } }),
getNextPageParam: lastPage => lastPage.nextPage,
});// Axios-style interceptors
client.interceptors.request.use((config) => {
config.headers.Authorization = `Bearer ${token}`;
return config;
});
client.interceptors.response.use((response) => {
console.log("Response received:", response);
return response;
});console.log(client.inspect());
client.invalidate(["user", 1]);
client.clearCache();Run the included benchmark to see the performance difference:
git clone https://github.com/ljlm0402/fynk.git
cd fynk
npm install
npm run benchThe benchmark prints a table with label, duration, calls, and scenario. Use the output from your own machine or CI as the source of truth.
Contributions are always welcome! Please feel free to open an issue or submit a pull request.
Made with β€οΈ by AGUMON π¦
