Overview
Angular’s resource APIs are designed to make asynchronous work feel native in a signal-driven application. Instead of manually wiring together booleans for loading, separate values for data, and extra error state, a resource centralizes that lifecycle into one reactive abstraction.
In practice, this means your components can describe what data depends on what input, and Angular keeps the resource synchronized when those dependencies change.
The resource model
Before looking at the two APIs, it helps to understand the pattern they share. A resource generally ties together:
Reactive input
A signal or computation determines the current request parameters. When the inputs change, the resource can fetch again.
Async loader
A loader obtains the actual data, whether through HttpClient, a custom async function, or an RxJS Observable pipeline.
State exposure
The resource exposes the current value, loading state, and failure state in a way that works naturally with templates and computed signals.
Refresh semantics
Resources are not just passive values. They also represent reloading, retries, and the transition between old and new server results.
What is httpResource?
httpResource is Angular’s signal-based wrapper for HTTP fetching.
It sits on top of HttpClient, which means it benefits from the same Angular HTTP stack:
interceptors, request configuration, testing tools, and familiar request semantics.
It is especially appealing when your component already uses signals for local state and computed values.
Instead of bridging between Observables and signals yourself, httpResource gives you a more direct path.
Typical mental model
- A signal determines the current URL or request config.
- The resource automatically refetches when that signal changes.
- Your template reads the resource’s status and current value reactively.
import { Component, computed, signal } from '@angular/core';
import { httpResource } from '@angular/common/http';
@Component({
selector: 'app-user-profile',
standalone: true,
template: `
<button (click)="userId.set(1)">User 1</button>
<button (click)="userId.set(2)">User 2</button>
@if (user.isLoading()) {
<p>Loading user...</p>
} @else if (user.error()) {
<p>Could not load user.</p>
} @else if (user.value()) {
<h3>{{ user.value()?.name }}</h3>
<p>{{ user.value()?.email }}</p>
}
`
})
export class UserProfileComponent {
userId = signal(1);
user = httpResource(() => `/api/users/${this.userId()}`);
}
That is the core appeal: the request itself becomes reactive.
What is rxResource?
rxResource follows the same broad resource pattern, but instead of wrapping
Angular HTTP requests directly, it uses an RxJS-based stream loader.
This makes it a strong fit when your data source already lives naturally in the Observable world.
For example, maybe your service already composes data with switchMap, combineLatest,
retry logic, caching, or custom stream operators. In those cases, rxResource lets you keep that
Observable-based design while still exposing the result through Angular’s resource abstraction.
rxResource is not “better” than httpResource. It is better when your async logic is
fundamentally stream-based or when you want to preserve an RxJS-centric architecture.
import { Component, inject, signal } from '@angular/core';
import { rxResource } from '@angular/core/rxjs-interop';
import { UserService } from './user.service';
@Component({
selector: 'app-user-details',
standalone: true,
template: `
@if (userResource.isLoading()) {
<p>Loading...</p>
} @else if (userResource.error()) {
<p>Request failed.</p>
} @else {
<pre>{{ userResource.value() | json }}</pre>
}
`
})
export class UserDetailsComponent {
private userService = inject(UserService);
userId = signal(42);
userResource = rxResource({
params: () => ({ id: this.userId() }),
stream: ({ params }) => this.userService.getUser(params.id)
});
}
Here, the service can continue returning an Observable, while the component consumes the result through resource semantics.
Key differences
| Aspect | httpResource | rxResource |
|---|---|---|
| Primary purpose | Reactive HTTP requests with Angular’s HttpClient stack. | Reactive resource values sourced from an RxJS Observable stream. |
| Best fit | Most straightforward server fetching in signal-based components. | Apps or services that already model async data heavily with RxJS. |
| Underlying model | HTTP request configuration and request lifecycle. | Observable composition and stream transformations. |
| Interceptors / HTTP stack | Yes — inherits standard Angular HTTP behavior. | Only indirectly, if the Observable itself comes from HttpClient. |
| Developer feel | Closer to “fetch this URL/request as signals.” | Closer to “expose this RxJS pipeline as a resource.” |
| Boilerplate | Usually lower for plain API calls. | Often lower when stream composition is already central. |
Practical examples
Use httpResource when…
You want a simple, declarative API call driven by one or more signals such as route params, search terms, selected IDs, pagination state, or filters.
Use rxResource when…
You already have Observable-based services, or your data needs operators like debounce, switchMap, retry, merge logic, or stream combination.
Example: reactive search with httpResource
search = signal('');
results = httpResource(() => {
const q = this.search().trim();
return q ? `/api/search?q=${encodeURIComponent(q)}` : undefined;
});
Returning undefined can be a clean way to avoid making a request until the user has entered a valid query.
Example: debounced search with rxResource
results = rxResource({
params: () => this.search(),
stream: ({ params }) =>
this.searchService.search(params).pipe(
// custom RxJS behavior could be handled here
// debounce, retry, mapping, fallback, etc.
)
});
This version makes more sense when the service is already designed around RxJS operators and stream composition.
When to use each
httpResource for direct API fetching in signal-based components.
Reach for rxResource when your async behavior is better expressed as an Observable pipeline.
Choose httpResource
- Your data comes from a normal HTTP endpoint.
- You want to stay close to Angular’s HttpClient conventions.
- You want request state without manual subscriptions.
- Your component already uses signals heavily.
Choose rxResource
- Your service API already returns Observables.
- You rely on RxJS transformations or combination.
- You want stream-oriented control over loading behavior.
- You are gradually bridging an RxJS-first codebase into signals.
Best practices
1. Keep request inputs explicit
Make the resource depend on clear signals such as IDs, filters, or route state. That makes re-fetch behavior predictable and easy to debug.
2. Avoid mixing patterns unnecessarily
If a feature is straightforward HTTP fetching, httpResource often reads better.
If it is already an RxJS pipeline, forcing it into another pattern may add complexity.
3. Design for loading and error UI
Resources shine when the template clearly handles pending, success, and failure states. Build those branches intentionally instead of treating them as afterthoughts.
4. Prefer services for business logic
Components should usually express dependency and display state. Shared fetching logic, mapping, and domain rules still belong in services.