Click Below to Get the Code

Browse, clone, and build from real-world templates powered by Harper.
Blog
GitHub Logo

The Resource API in Harper v5: HTTP Done Right

Harper v5's Resource API maps JavaScript class methods directly to HTTP verbs, eliminating routing and translation layers. Tables extend the same Resource class, unifying HTTP handling and data access into one interface. Key v5 additions include pre-parsed RequestTarget objects, Response-aware source caching with stale-while-revalidate support, and async context tracking via getContext().
Product Update
Blog
Product Update

The Resource API in Harper v5: HTTP Done Right

By
Kris Zyp
April 14, 2026
By
Kris Zyp
April 14, 2026
By
Kris Zyp
April 14, 2026
April 14, 2026
Harper v5's Resource API maps JavaScript class methods directly to HTTP verbs, eliminating routing and translation layers. Tables extend the same Resource class, unifying HTTP handling and data access into one interface. Key v5 additions include pre-parsed RequestTarget objects, Response-aware source caching with stale-while-revalidate support, and async context tracking via getContext().
Kris Zyp
SVP of Engineering

There is a gap that shows up consistently in application frameworks between what HTTP actually specifies and what the framework exposes to developers. HTTP's uniform interface — GET, PUT, PATCH, POST, DELETE — is precise and well-reasoned. The semantics are defined. The contract is clear. But most frameworks layer their own routing and handler abstractions on top, and the correspondence between what HTTP says and what your code does becomes indirect. You end up mapping between two systems rather than working in one.

Harper's Resource API closes that gap. In v5, it does so more directly than any previous version.

The Uniform Interface, Directly Expressed

The Resource API is a JavaScript class interface where static methods map one-to-one to HTTP verbs. A Resource class represents a collection; a Resource instance represents a single record. To define how your application responds to HTTP requests, you extend the base Resource class and override the methods that correspond to the HTTP verbs you care about.

class Product extends Resource {
    static async get(target) {
        // called for HTTP GET /Product/:id
        return super.get(target);
    }

    static async put(target, data) {
        // called for HTTP PUT /Product/:id
        return super.put(target, { ...(await data), status: 'active' });
    }

    static async delete(target) {
        // called for HTTP DELETE /Product/:id
        return super.delete(target);
    }
}

This is not a coincidence of naming. The static methods are the HTTP handlers. Harper routes incoming requests directly to these methods. There is no separate routing layer, no middleware registration, no controller-to-method mapping to maintain. The class structure encodes the URL hierarchy; the method names encode the HTTP verbs.

v5 formalizes this further by explicitly encouraging use of static methods as the primary interaction pattern, and by pre-parsing the RequestTarget before it reaches any static method. That second point matters more than it might seem.

The RequestTarget as Parsed URL

In v5, when a request arrives, Harper parses the URL into a RequestTarget object before calling your static method. RequestTarget is a subclass of URLSearchParams, so it carries the full query string as a native iterable interface, plus additional properties that Harper derives from the URL structure:

  • target.id — the primary key extracted from the path
  • target.pathname — the path portion relative to the resource
  • target.isCollectiontrue when the request targets a collection (e.g. /Product/ with query conditions) rather than a single record
  • target.conditions, target.limit, target.offset, target.sort, target.select — query parameters parsed from Harper's extended URL query syntax

The consequence is that your get method does not need to parse anything. The URL has already been translated into a structured object that reflects the semantics of the request.

static get(target) {
    const id = target.id;
    const filter = target.get('status');  // standard URLSearchParams access
    const limit = target.limit;           // parsed by Harper from URL syntax
    return super.get(target);
}

Compare this to the alternative: receiving a raw URL string, manually extracting path segments, manually parsing query parameters, and then constructing some internal query object from what you found. The RequestTarget design eliminates that translation layer. What HTTP says about the request is what your method receives.

Data Modeling Through the Resource Interface

The Resource API is also the primary modeling interface for data. Tables in Harper extend Resource, which means the same methods that handle HTTP requests are the methods you use to interact with data from application code. There is one interface, not two.

Static methods handle reads and writes at the collection level:

// retrieve a single record
const product = await Product.get(34);

// partial update
await Product.patch(34, { description: 'Updated description' });

// full replacement
await Product.put({ id: 34, name: 'New Product Name', price: 49.99 });

// create with auto-generated key
const created = await Product.create({ name: 'New Product', price: 29.99 });

// delete
await Product.delete(34);

Instance methods, retrieved via update(), allow mutable access to a single record within a transaction:

const product = await Product.update(32);
product.status = 'active';
product.subtractFrom('quantity', 1);  // CRDT-safe decrement
product.save();                        // explicit save within transaction

The save() method is new in v5. Previously, pending changes were committed only when the transaction completed. save() makes those changes visible to subsequent reads and queries within the same transaction — useful when you need to write a record and then query against the updated state before the transaction closes.

The get() method in v5 returns a RecordObject: a frozen plain object containing the record's properties plus getUpdatedTime() and getExpiresAt(). It is immutable. This is intentional. The returned object represents the committed state of the record in the database; mutation belongs to the update() flow. If you need a modified version of the record for a response, the spread operator is the explicit path:

static async get(target) {
    const record = await super.get(target);
    return { ...record, computedField: derive(record) };
}

The consistency here — a frozen read result, a distinct mutable update path — reflects the underlying transaction model. Reads are snapshots. Writes are transactions. The API makes that distinction explicit.

Caching and Sourcing: Where the Model Gets Interesting

The Resource API's treatment of caching is where the data modeling story becomes most useful. Harper supports the concept of a source resource: a resource that a caching table delegates to when a record is not found locally. This is configured with sourcedFrom():

ProductCache.sourcedFrom(ExternalProductAPI, {
    expiration: 300,   // TTL in seconds
    eviction: 3600     // eviction time in seconds
});

Once configured, reads against ProductCache transparently check local storage first, fall back to ExternalProductAPI if there is a miss, cache the result, and serve subsequent requests from local storage until expiration. Writes are delegated upstream.

The v5 changes to how source resources work make this pattern significantly more practical.

Returning a Response Object from Source

A source resource's get method can now return a standard Response object — the same type you get from a fetch() call. Harper will stream the response body and save the headers into the cached record automatically.

class ExternalProductAPI extends Resource {
    static async get(target) {
        const response = await fetch(`https://api.example.com/products/${target.id}`);
        return response;  // Harper handles streaming and header caching
    }
}

This matters because most upstream data sources are HTTP APIs. Previously, you had to extract the body, parse it, and return a plain object — discarding headers that might carry semantic information (caching directives, content type, custom metadata). Now the full response is preserved. If the upstream API returns Cache-Control or ETag headers, those are stored and can inform downstream caching behavior.

The getResponse() function, available as a named export from the harper module, provides access to the response object from within a resource method when you need it. You can use wasLoadedFromSource() on the instance to determine whether the current request was a cache miss — useful when you want to behave differently on cold cache versus warm cache.

Stale-While-Revalidate

The allowStaleWhileRevalidate() method gives you control over cache freshness policy at the record level:

static allowStaleWhileRevalidate(entry, id) {
    // serve the stale entry immediately while revalidation runs in the background
    return (Date.now() - entry.localTime) < 60_000;  // stale for less than 60s
}

When this returns true, Harper serves the cached value immediately and triggers a background refresh. When it returns false, the request waits for the fresh value. The entry object includes version, localTime, expiresAt, and value, giving you the information needed to make this decision per-record rather than globally.

The combination of source delegation, Response object handling, and stale-while-revalidate control gives you a caching layer that is not bolted on but is expressed through the same method interface as everything else in the API.

Context Without Threading

One of the practical complications in multi-request server environments is getting access to the current request from code that is not the immediate handler. If you have a utility function five calls deep in a call chain, and you need the request's authentication token or user context, the common solution is to pass the request object as a parameter through every intermediate function. This works but it is noise — most functions do not need the request, they just relay it to the next level.

v5 solves this with asynchronous context tracking. getContext(), available as a named export from the harper module or as a global, returns the current Request object — the one associated with whatever async execution context is currently running. No parameter passing required.

import { getContext } from 'harper';

function someUtilityDeepInTheCallChain() {
    const context = getContext();
    const userRole = context.user.role;
    // act on user authorization without having received request as a parameter
}

When triggered by HTTP, the context is the Request object with properties for method, headers, responseHeaders, url, ip, host, body, and data. You can set response headers through context.responseHeaders.set() from anywhere in the async context — another case where the alternative is passing state through intermediate layers.

This is the Node.js AsyncLocalStorage API applied consistently throughout Harper's request lifecycle. The mechanism is not novel, but the fact that Harper exposes it through the standard getContext() export means you do not have to set it up yourself.

The Benefits, in Summary

The Resource API's design choices compound. Because static methods map directly to HTTP verbs, there is no translation layer between what the HTTP client requests and what your code handles. Because RequestTarget arrives pre-parsed, URL interpretation is not your responsibility. Because the same methods work for both HTTP handling and programmatic data access, there is one mental model for both concerns. Because source resources can return Response objects, the caching layer preserves upstream HTTP semantics rather than discarding them. Because getContext() uses async context tracking, request state is accessible without explicit parameter threading.

None of these are individually unprecedented. What the Resource API does is combine them into a consistent interface where each decision reinforces the others. The HTTP uniform interface — which is precise and well-specified — becomes the application's data interface as well. That alignment reduces the surface area for inconsistency, and it reduces the amount of glue code that does nothing but translate between layers.

I am most interested to see how teams use the source resource pattern as systems scale. The caching and sourcing model is expressive enough to handle a range of architectures — local caching of remote APIs, tiered storage, conditional revalidation based on record-level logic — and I think the combinations people reach for in practice will be more varied than what we have anticipated.

The v5 Resource API documentation covers the full method signatures and options.

There is a gap that shows up consistently in application frameworks between what HTTP actually specifies and what the framework exposes to developers. HTTP's uniform interface — GET, PUT, PATCH, POST, DELETE — is precise and well-reasoned. The semantics are defined. The contract is clear. But most frameworks layer their own routing and handler abstractions on top, and the correspondence between what HTTP says and what your code does becomes indirect. You end up mapping between two systems rather than working in one.

Harper's Resource API closes that gap. In v5, it does so more directly than any previous version.

The Uniform Interface, Directly Expressed

The Resource API is a JavaScript class interface where static methods map one-to-one to HTTP verbs. A Resource class represents a collection; a Resource instance represents a single record. To define how your application responds to HTTP requests, you extend the base Resource class and override the methods that correspond to the HTTP verbs you care about.

class Product extends Resource {
    static async get(target) {
        // called for HTTP GET /Product/:id
        return super.get(target);
    }

    static async put(target, data) {
        // called for HTTP PUT /Product/:id
        return super.put(target, { ...(await data), status: 'active' });
    }

    static async delete(target) {
        // called for HTTP DELETE /Product/:id
        return super.delete(target);
    }
}

This is not a coincidence of naming. The static methods are the HTTP handlers. Harper routes incoming requests directly to these methods. There is no separate routing layer, no middleware registration, no controller-to-method mapping to maintain. The class structure encodes the URL hierarchy; the method names encode the HTTP verbs.

v5 formalizes this further by explicitly encouraging use of static methods as the primary interaction pattern, and by pre-parsing the RequestTarget before it reaches any static method. That second point matters more than it might seem.

The RequestTarget as Parsed URL

In v5, when a request arrives, Harper parses the URL into a RequestTarget object before calling your static method. RequestTarget is a subclass of URLSearchParams, so it carries the full query string as a native iterable interface, plus additional properties that Harper derives from the URL structure:

  • target.id — the primary key extracted from the path
  • target.pathname — the path portion relative to the resource
  • target.isCollectiontrue when the request targets a collection (e.g. /Product/ with query conditions) rather than a single record
  • target.conditions, target.limit, target.offset, target.sort, target.select — query parameters parsed from Harper's extended URL query syntax

The consequence is that your get method does not need to parse anything. The URL has already been translated into a structured object that reflects the semantics of the request.

static get(target) {
    const id = target.id;
    const filter = target.get('status');  // standard URLSearchParams access
    const limit = target.limit;           // parsed by Harper from URL syntax
    return super.get(target);
}

Compare this to the alternative: receiving a raw URL string, manually extracting path segments, manually parsing query parameters, and then constructing some internal query object from what you found. The RequestTarget design eliminates that translation layer. What HTTP says about the request is what your method receives.

Data Modeling Through the Resource Interface

The Resource API is also the primary modeling interface for data. Tables in Harper extend Resource, which means the same methods that handle HTTP requests are the methods you use to interact with data from application code. There is one interface, not two.

Static methods handle reads and writes at the collection level:

// retrieve a single record
const product = await Product.get(34);

// partial update
await Product.patch(34, { description: 'Updated description' });

// full replacement
await Product.put({ id: 34, name: 'New Product Name', price: 49.99 });

// create with auto-generated key
const created = await Product.create({ name: 'New Product', price: 29.99 });

// delete
await Product.delete(34);

Instance methods, retrieved via update(), allow mutable access to a single record within a transaction:

const product = await Product.update(32);
product.status = 'active';
product.subtractFrom('quantity', 1);  // CRDT-safe decrement
product.save();                        // explicit save within transaction

The save() method is new in v5. Previously, pending changes were committed only when the transaction completed. save() makes those changes visible to subsequent reads and queries within the same transaction — useful when you need to write a record and then query against the updated state before the transaction closes.

The get() method in v5 returns a RecordObject: a frozen plain object containing the record's properties plus getUpdatedTime() and getExpiresAt(). It is immutable. This is intentional. The returned object represents the committed state of the record in the database; mutation belongs to the update() flow. If you need a modified version of the record for a response, the spread operator is the explicit path:

static async get(target) {
    const record = await super.get(target);
    return { ...record, computedField: derive(record) };
}

The consistency here — a frozen read result, a distinct mutable update path — reflects the underlying transaction model. Reads are snapshots. Writes are transactions. The API makes that distinction explicit.

Caching and Sourcing: Where the Model Gets Interesting

The Resource API's treatment of caching is where the data modeling story becomes most useful. Harper supports the concept of a source resource: a resource that a caching table delegates to when a record is not found locally. This is configured with sourcedFrom():

ProductCache.sourcedFrom(ExternalProductAPI, {
    expiration: 300,   // TTL in seconds
    eviction: 3600     // eviction time in seconds
});

Once configured, reads against ProductCache transparently check local storage first, fall back to ExternalProductAPI if there is a miss, cache the result, and serve subsequent requests from local storage until expiration. Writes are delegated upstream.

The v5 changes to how source resources work make this pattern significantly more practical.

Returning a Response Object from Source

A source resource's get method can now return a standard Response object — the same type you get from a fetch() call. Harper will stream the response body and save the headers into the cached record automatically.

class ExternalProductAPI extends Resource {
    static async get(target) {
        const response = await fetch(`https://api.example.com/products/${target.id}`);
        return response;  // Harper handles streaming and header caching
    }
}

This matters because most upstream data sources are HTTP APIs. Previously, you had to extract the body, parse it, and return a plain object — discarding headers that might carry semantic information (caching directives, content type, custom metadata). Now the full response is preserved. If the upstream API returns Cache-Control or ETag headers, those are stored and can inform downstream caching behavior.

The getResponse() function, available as a named export from the harper module, provides access to the response object from within a resource method when you need it. You can use wasLoadedFromSource() on the instance to determine whether the current request was a cache miss — useful when you want to behave differently on cold cache versus warm cache.

Stale-While-Revalidate

The allowStaleWhileRevalidate() method gives you control over cache freshness policy at the record level:

static allowStaleWhileRevalidate(entry, id) {
    // serve the stale entry immediately while revalidation runs in the background
    return (Date.now() - entry.localTime) < 60_000;  // stale for less than 60s
}

When this returns true, Harper serves the cached value immediately and triggers a background refresh. When it returns false, the request waits for the fresh value. The entry object includes version, localTime, expiresAt, and value, giving you the information needed to make this decision per-record rather than globally.

The combination of source delegation, Response object handling, and stale-while-revalidate control gives you a caching layer that is not bolted on but is expressed through the same method interface as everything else in the API.

Context Without Threading

One of the practical complications in multi-request server environments is getting access to the current request from code that is not the immediate handler. If you have a utility function five calls deep in a call chain, and you need the request's authentication token or user context, the common solution is to pass the request object as a parameter through every intermediate function. This works but it is noise — most functions do not need the request, they just relay it to the next level.

v5 solves this with asynchronous context tracking. getContext(), available as a named export from the harper module or as a global, returns the current Request object — the one associated with whatever async execution context is currently running. No parameter passing required.

import { getContext } from 'harper';

function someUtilityDeepInTheCallChain() {
    const context = getContext();
    const userRole = context.user.role;
    // act on user authorization without having received request as a parameter
}

When triggered by HTTP, the context is the Request object with properties for method, headers, responseHeaders, url, ip, host, body, and data. You can set response headers through context.responseHeaders.set() from anywhere in the async context — another case where the alternative is passing state through intermediate layers.

This is the Node.js AsyncLocalStorage API applied consistently throughout Harper's request lifecycle. The mechanism is not novel, but the fact that Harper exposes it through the standard getContext() export means you do not have to set it up yourself.

The Benefits, in Summary

The Resource API's design choices compound. Because static methods map directly to HTTP verbs, there is no translation layer between what the HTTP client requests and what your code handles. Because RequestTarget arrives pre-parsed, URL interpretation is not your responsibility. Because the same methods work for both HTTP handling and programmatic data access, there is one mental model for both concerns. Because source resources can return Response objects, the caching layer preserves upstream HTTP semantics rather than discarding them. Because getContext() uses async context tracking, request state is accessible without explicit parameter threading.

None of these are individually unprecedented. What the Resource API does is combine them into a consistent interface where each decision reinforces the others. The HTTP uniform interface — which is precise and well-specified — becomes the application's data interface as well. That alignment reduces the surface area for inconsistency, and it reduces the amount of glue code that does nothing but translate between layers.

I am most interested to see how teams use the source resource pattern as systems scale. The caching and sourcing model is expressive enough to handle a range of architectures — local caching of remote APIs, tiered storage, conditional revalidation based on record-level logic — and I think the combinations people reach for in practice will be more varied than what we have anticipated.

The v5 Resource API documentation covers the full method signatures and options.

Harper v5's Resource API maps JavaScript class methods directly to HTTP verbs, eliminating routing and translation layers. Tables extend the same Resource class, unifying HTTP handling and data access into one interface. Key v5 additions include pre-parsed RequestTarget objects, Response-aware source caching with stale-while-revalidate support, and async context tracking via getContext().

Download

White arrow pointing right
Harper v5's Resource API maps JavaScript class methods directly to HTTP verbs, eliminating routing and translation layers. Tables extend the same Resource class, unifying HTTP handling and data access into one interface. Key v5 additions include pre-parsed RequestTarget objects, Response-aware source caching with stale-while-revalidate support, and async context tracking via getContext().

Download

White arrow pointing right
Harper v5's Resource API maps JavaScript class methods directly to HTTP verbs, eliminating routing and translation layers. Tables extend the same Resource class, unifying HTTP handling and data access into one interface. Key v5 additions include pre-parsed RequestTarget objects, Response-aware source caching with stale-while-revalidate support, and async context tracking via getContext().

Download

White arrow pointing right

Explore Recent Resources

Blog
GitHub Logo

The Resource API in Harper v5: HTTP Done Right

Harper v5's Resource API maps JavaScript class methods directly to HTTP verbs, eliminating routing and translation layers. Tables extend the same Resource class, unifying HTTP handling and data access into one interface. Key v5 additions include pre-parsed RequestTarget objects, Response-aware source caching with stale-while-revalidate support, and async context tracking via getContext().
Product Update
Blog
Harper v5's Resource API maps JavaScript class methods directly to HTTP verbs, eliminating routing and translation layers. Tables extend the same Resource class, unifying HTTP handling and data access into one interface. Key v5 additions include pre-parsed RequestTarget objects, Response-aware source caching with stale-while-revalidate support, and async context tracking via getContext().
Person with very short blonde hair wearing a light gray button‑up shirt, standing with arms crossed and smiling outdoors with foliage behind.
Kris Zyp
SVP of Engineering
Blog

The Resource API in Harper v5: HTTP Done Right

Harper v5's Resource API maps JavaScript class methods directly to HTTP verbs, eliminating routing and translation layers. Tables extend the same Resource class, unifying HTTP handling and data access into one interface. Key v5 additions include pre-parsed RequestTarget objects, Response-aware source caching with stale-while-revalidate support, and async context tracking via getContext().
Kris Zyp
Apr 2026
Blog

The Resource API in Harper v5: HTTP Done Right

Harper v5's Resource API maps JavaScript class methods directly to HTTP verbs, eliminating routing and translation layers. Tables extend the same Resource class, unifying HTTP handling and data access into one interface. Key v5 additions include pre-parsed RequestTarget objects, Response-aware source caching with stale-while-revalidate support, and async context tracking via getContext().
Kris Zyp
Blog

The Resource API in Harper v5: HTTP Done Right

Harper v5's Resource API maps JavaScript class methods directly to HTTP verbs, eliminating routing and translation layers. Tables extend the same Resource class, unifying HTTP handling and data access into one interface. Key v5 additions include pre-parsed RequestTarget objects, Response-aware source caching with stale-while-revalidate support, and async context tracking via getContext().
Kris Zyp
News
GitHub Logo

Harper 5.0 Is Here: Open Source, RocksDB, and a Runtime Built for the Agentic Era

Harper 5.0 launches with a fully open-source core under Apache 2.0, RocksDB as a native storage engine alongside LMDB, and source-available Harper Pro. This release delivers a unified runtime purpose-built for agentic engineering, from prototype to production.
Product Update
News
Harper 5.0 launches with a fully open-source core under Apache 2.0, RocksDB as a native storage engine alongside LMDB, and source-available Harper Pro. This release delivers a unified runtime purpose-built for agentic engineering, from prototype to production.
Person with short dark hair and moustache, wearing a colorful plaid shirt, smiling outdoors in a forested mountain landscape.
Aleks Haugom
Senior Manager of GTM & Marketing
News

Harper 5.0 Is Here: Open Source, RocksDB, and a Runtime Built for the Agentic Era

Harper 5.0 launches with a fully open-source core under Apache 2.0, RocksDB as a native storage engine alongside LMDB, and source-available Harper Pro. This release delivers a unified runtime purpose-built for agentic engineering, from prototype to production.
Aleks Haugom
Apr 2026
News

Harper 5.0 Is Here: Open Source, RocksDB, and a Runtime Built for the Agentic Era

Harper 5.0 launches with a fully open-source core under Apache 2.0, RocksDB as a native storage engine alongside LMDB, and source-available Harper Pro. This release delivers a unified runtime purpose-built for agentic engineering, from prototype to production.
Aleks Haugom
News

Harper 5.0 Is Here: Open Source, RocksDB, and a Runtime Built for the Agentic Era

Harper 5.0 launches with a fully open-source core under Apache 2.0, RocksDB as a native storage engine alongside LMDB, and source-available Harper Pro. This release delivers a unified runtime purpose-built for agentic engineering, from prototype to production.
Aleks Haugom
Podcast
GitHub Logo

Maintaining Momentum: Versioning, Stability & the Road to Nuxt 5 with Daniel Roe

In this podcast episode, Daniel Roe, lead of the Nuxt framework, shares insights on Nuxt 3, 4, and the upcoming Nuxt 5 release. We discuss open-source development, upgrading Nuxt apps, Vue-powered full-stack web apps, version maintenance, and the future of modern web development.
Select*
Podcast
In this podcast episode, Daniel Roe, lead of the Nuxt framework, shares insights on Nuxt 3, 4, and the upcoming Nuxt 5 release. We discuss open-source development, upgrading Nuxt apps, Vue-powered full-stack web apps, version maintenance, and the future of modern web development.
Person with short hair wearing a light blue patterned shirt, smiling widely outdoors with blurred greenery and trees in the background.
Austin Akers
Head of Developer Relations
Podcast

Maintaining Momentum: Versioning, Stability & the Road to Nuxt 5 with Daniel Roe

In this podcast episode, Daniel Roe, lead of the Nuxt framework, shares insights on Nuxt 3, 4, and the upcoming Nuxt 5 release. We discuss open-source development, upgrading Nuxt apps, Vue-powered full-stack web apps, version maintenance, and the future of modern web development.
Austin Akers
Apr 2026
Podcast

Maintaining Momentum: Versioning, Stability & the Road to Nuxt 5 with Daniel Roe

In this podcast episode, Daniel Roe, lead of the Nuxt framework, shares insights on Nuxt 3, 4, and the upcoming Nuxt 5 release. We discuss open-source development, upgrading Nuxt apps, Vue-powered full-stack web apps, version maintenance, and the future of modern web development.
Austin Akers
Podcast

Maintaining Momentum: Versioning, Stability & the Road to Nuxt 5 with Daniel Roe

In this podcast episode, Daniel Roe, lead of the Nuxt framework, shares insights on Nuxt 3, 4, and the upcoming Nuxt 5 release. We discuss open-source development, upgrading Nuxt apps, Vue-powered full-stack web apps, version maintenance, and the future of modern web development.
Austin Akers
Blog
GitHub Logo

Most LLM Calls Are Waste. Here's the Math.

Semantic caching for LLMs can reduce API costs by 20–70% by reusing similar responses. Combined with deterministic routing and improved retrieval, enterprises can significantly lower LLM usage, though effectiveness varies by workload and improves over time.
Blog
Semantic caching for LLMs can reduce API costs by 20–70% by reusing similar responses. Combined with deterministic routing and improved retrieval, enterprises can significantly lower LLM usage, though effectiveness varies by workload and improves over time.
Person with short dark hair and moustache, wearing a colorful plaid shirt, smiling outdoors in a forested mountain landscape.
Aleks Haugom
Senior Manager of GTM & Marketing
Blog

Most LLM Calls Are Waste. Here's the Math.

Semantic caching for LLMs can reduce API costs by 20–70% by reusing similar responses. Combined with deterministic routing and improved retrieval, enterprises can significantly lower LLM usage, though effectiveness varies by workload and improves over time.
Aleks Haugom
Apr 2026
Blog

Most LLM Calls Are Waste. Here's the Math.

Semantic caching for LLMs can reduce API costs by 20–70% by reusing similar responses. Combined with deterministic routing and improved retrieval, enterprises can significantly lower LLM usage, though effectiveness varies by workload and improves over time.
Aleks Haugom
Blog

Most LLM Calls Are Waste. Here's the Math.

Semantic caching for LLMs can reduce API costs by 20–70% by reusing similar responses. Combined with deterministic routing and improved retrieval, enterprises can significantly lower LLM usage, though effectiveness varies by workload and improves over time.
Aleks Haugom
Blog
GitHub Logo

Build a Conversational AI Agent on Harper in 5 Minutes

Build a conversational AI agent in minutes using Harper’s unified platform. This guide shows how to create, deploy, and scale real-time AI agents with built-in database, vector search, and APIs—eliminating infrastructure complexity for faster development.
Blog
Build a conversational AI agent in minutes using Harper’s unified platform. This guide shows how to create, deploy, and scale real-time AI agents with built-in database, vector search, and APIs—eliminating infrastructure complexity for faster development.
A smiling man with a beard and salt-and-pepper hair stands outdoors with arms crossed, wearing a white button-down shirt.
Stephen Goldberg
CEO & Co-Founder
Blog

Build a Conversational AI Agent on Harper in 5 Minutes

Build a conversational AI agent in minutes using Harper’s unified platform. This guide shows how to create, deploy, and scale real-time AI agents with built-in database, vector search, and APIs—eliminating infrastructure complexity for faster development.
Stephen Goldberg
Apr 2026
Blog

Build a Conversational AI Agent on Harper in 5 Minutes

Build a conversational AI agent in minutes using Harper’s unified platform. This guide shows how to create, deploy, and scale real-time AI agents with built-in database, vector search, and APIs—eliminating infrastructure complexity for faster development.
Stephen Goldberg
Blog

Build a Conversational AI Agent on Harper in 5 Minutes

Build a conversational AI agent in minutes using Harper’s unified platform. This guide shows how to create, deploy, and scale real-time AI agents with built-in database, vector search, and APIs—eliminating infrastructure complexity for faster development.
Stephen Goldberg
Podcast
GitHub Logo

Inside PixiJS, AT Protocol, and Modern Game Development with Trezy Who

Trezy shares his journey from professional drummer and filmmaker to software engineer and open source maintainer. Learn about PixieJS, game development, AT Proto, BlueSky, data sovereignty, and how developers can confidently contribute to open source projects.
Select*
Podcast
Trezy shares his journey from professional drummer and filmmaker to software engineer and open source maintainer. Learn about PixieJS, game development, AT Proto, BlueSky, data sovereignty, and how developers can confidently contribute to open source projects.
Person with short hair wearing a light blue patterned shirt, smiling widely outdoors with blurred greenery and trees in the background.
Austin Akers
Head of Developer Relations
Podcast

Inside PixiJS, AT Protocol, and Modern Game Development with Trezy Who

Trezy shares his journey from professional drummer and filmmaker to software engineer and open source maintainer. Learn about PixieJS, game development, AT Proto, BlueSky, data sovereignty, and how developers can confidently contribute to open source projects.
Austin Akers
Mar 2026
Podcast

Inside PixiJS, AT Protocol, and Modern Game Development with Trezy Who

Trezy shares his journey from professional drummer and filmmaker to software engineer and open source maintainer. Learn about PixieJS, game development, AT Proto, BlueSky, data sovereignty, and how developers can confidently contribute to open source projects.
Austin Akers
Podcast

Inside PixiJS, AT Protocol, and Modern Game Development with Trezy Who

Trezy shares his journey from professional drummer and filmmaker to software engineer and open source maintainer. Learn about PixieJS, game development, AT Proto, BlueSky, data sovereignty, and how developers can confidently contribute to open source projects.
Austin Akers