TransferState API
TransferState caches server-side data in the rendered HTML to avoid duplicate client requests during hydration.
How TransferState Works
- Server fetches data and stores it in TransferState
- TransferState serializes data into the HTML (as a script tag)
- Client reads the data from TransferState during hydration
- Client uses cached data instead of making a duplicate request
Using TransferState
import { TransferState, makeStateKey } from '@angular/core';
import { isPlatformServer } from '@angular/common';
const USERS_KEY = makeStateKey<User[]>('users');
@Injectable({ providedIn: 'root' })
export class UserService {
private http = inject(HttpClient);
private transferState = inject(TransferState);
private platformId = inject(PLATFORM_ID);
getUsers(): Observable<User[]> {
// Check if data was transferred from server
if (this.transferState.hasKey(USERS_KEY)) {
const users = this.transferState.get(USERS_KEY, [] as User[]);
this.transferState.remove(USERS_KEY);
return of(users);
}
// Fetch from API
return this.http.get<User[]>('/api/users').pipe(
tap(users => {
// Store in TransferState on server
if (isPlatformServer(this.platformId)) {
this.transferState.set(USERS_KEY, users);
}
})
);
}
}
makeStateKey
const USERS_KEY = makeStateKey<User[]>('users');
const CONFIG_KEY = makeStateKey<AppConfig>('config');
makeStateKey creates a typed key for reading and writing TransferState.
TransferState Methods
| Method | Purpose |
|---|---|
set(key, value) |
Store data |
get(key, defaultValue) |
Read data |
hasKey(key) |
Check if key exists |
remove(key) |
Delete key |
serialize() |
Export all state as JSON |
Practical TransferState Patterns
TransferState is most useful for read-only API data that both server and client need.
Server-Side Data Fetching
// On the server, fetch data before rendering
@Component({
selector: 'app-product-list',
template: `<p *ngFor="let product of products">{{ product.name }}</p>`,
})
export class ProductListComponent implements OnInit {
products: Product[] = [];
constructor(
private productService: ProductService,
private transferState: TransferState,
@Inject(PLATFORM_ID) private platformId: Object,
) {}
ngOnInit(): void {
this.productService.getProducts().subscribe(products => {
this.products = products;
if (isPlatformServer(this.platformId)) {
this.transferState.set(PRODUCTS_KEY, products);
}
});
}
}
Benefits of TransferState
- No duplicate requests — Client uses server-fetched data
- Faster perceived load — Data is already in the HTML
- Reduced server load — Fewer API calls from the client
- Consistent state — Server and client see the same data
When to Use TransferState
- Read-only API data needed on both server and client
- Configuration data
- User profile data
- Product catalog data
When NOT to Use TransferState
- Data that changes frequently
- User-specific mutable data
- Real-time data (WebSockets)
Quiz
1. What does TransferState do?
2. What is makeStateKey used for?
3. When should you use TransferState?
Flashcards
Question
What does TransferState do?
Click to reveal answer
Answer
Embeds server data in HTML. Client uses it instead of duplicate requests.
Question
What is makeStateKey?
Click to reveal answer
Answer
Creates typed keys for TransferState read/write.
Question
When to use TransferState?
Click to reveal answer
Answer
Read-only data needed on both server and client.
Revision Notes
Key Takeaways
- 1. TransferState embeds server data in HTML
- 2. makeStateKey creates typed keys
- 3. Avoids duplicate client requests
- 4. Best for read-only data needed on both sides
Interview Tips
- • Explain the TransferState flow
- • Be ready to describe when to use it
- • Mention the performance benefits
Cheat Sheet
TransferState Cheat Sheet
Create key:
const USERS_KEY = makeStateKey<User[]>('users');
Server: store data:
if (isPlatformServer(this.platformId)) {
this.transferState.set(USERS_KEY, users);
}
Client: read data:
if (this.transferState.hasKey(USERS_KEY)) {
const users = this.transferState.get(USERS_KEY, []);
this.transferState.remove(USERS_KEY);
}