A modern, type-safe TypeScript client for the Federal Reserve Economic Data (FRED) API.
Getting Started:
- Installation - Install and setup
- Quick Start - Basic usage example
- Usage Examples - Common patterns
Documentation:
- Configuration - Client configuration options
- Pagination - Paginating through results
- Error Handling - Handling API errors
- API Reference - Complete API documentation
Examples:
- Fetching Series Data - Working with time series
- Pagination Patterns - Handling large result sets
Contributing:
- CONTRIBUTING.md - Contributor guide (≤15 min setup)
- ✅ Zero runtime dependencies - Uses native Node.js Fetch API
- ✅ TypeScript-first - Built with TypeScript 5.9.x strict mode
- ✅ Dual module format - ESM and CJS support via tsup
- ✅ 1:1 FRED API mapping - Direct correspondence to FRED endpoints
- ✅ Automatic retry - Exponential backoff with jitter (opt-in)
- ✅ Rate limiting - Token bucket algorithm (opt-in)
- ✅ In-memory caching - TTL-based caching (opt-in)
- ✅ Type-safe - Runtime validation with detailed error messages
- ✅ Auto-pagination - Async iterators for paginated results
- ✅ Security-first - Automatic API key redaction in errors
npm install @mjesuele/fred-clientRequirements:
- Node.js 20+ or 22 LTS
- A FRED API key (get one free here)
import { FREDClient } from "@mjesuele/fred-client";
// Create a client
const client = new FREDClient({
apiKey: "your-api-key-here",
});
// Get series metadata
const gdp = await client.series.get({ seriesId: "GDP" });
console.log(gdp.title); // "Gross Domestic Product"
console.log(gdp.units); // "Billions of Dollars"
console.log(gdp.frequency); // "Quarterly"
// Get observations (data points)
const observations = await client.series.getObservations({
seriesId: "GDP",
observationStart: "2020-01-01",
observationEnd: "2023-12-31",
});
// observations is an array of { date, value } objects
for (const obs of observations) {
console.log(`${obs.date}: ${obs.value}`);
}
// Search for series
const searchResults = await client.series.search({
searchText: "unemployment rate",
limit: 10,
});
console.log(`Found ${searchResults.metadata.count} series`);
for (const series of searchResults.data) {
console.log(`${series.id}: ${series.title}`);
}// Get root category
const root = await client.categories.get();
// Get child categories
const children = await client.categories.getChildren({
categoryId: 0,
limit: 10,
});
// Get series in a category
const series = await client.categories.getSeries({
categoryId: 125,
limit: 20,
});// Search for series
const results = await client.series.search({
searchText: "unemployment rate",
limit: 10,
});
// Get series with specific tags
const taggedSeries = await client.series.search({
searchText: "gdp",
tagNames: ["quarterly", "usa"],
});
// Get series metadata
const series = await client.series.get({ seriesId: "UNRATE" });
// Get observations with date range
const obs = await client.series.getObservations({
seriesId: "UNRATE",
observationStart: "2023-01-01",
limit: 100,
});// List all releases
const releases = await client.releases.list({ limit: 50 });
// Get a specific release
const release = await client.releases.get({ releaseId: 50 });
// Get release dates
const dates = await client.releases.getDates({
releaseId: 50,
includeReleaseDatesWithNoData: false,
});
// Get series in a release
const series = await client.releases.getSeries({
releaseId: 50,
limit: 20,
});// Manually handle pagination
const page1 = await client.series.search({
searchText: "inflation",
limit: 100,
offset: 0,
});
const page2 = await client.series.search({
searchText: "inflation",
limit: 100,
offset: 100,
});
// Or use async iterator for automatic pagination
for await (const batch of client.series.searchIterate({
searchText: "inflation",
limit: 100,
})) {
// Process each batch of 100 results
console.log(`Processing ${batch.length} results`);
}const client = new FREDClient({
apiKey: "your-api-key",
baseUrl: "https://api.stlouisfed.org/fred", // Optional, uses default
});const client = new FREDClient({
apiKey: "your-api-key",
retry: {
maxRetries: 3,
initialDelayMs: 1000,
maxDelayMs: 10000,
retryableStatusCodes: [429, 500, 502, 503, 504],
},
});const client = new FREDClient({
apiKey: "your-api-key",
rateLimit: {
requestsPerSecond: 5,
burstSize: 10,
},
});const client = new FREDClient({
apiKey: "your-api-key",
cache: {
ttlSeconds: 300, // 5 minutes
maxEntries: 1000, // Max cached responses
keyPrefix: "fred:", // Cache key prefix
},
});import { fetch as undiciFetch } from "undici";
const client = new FREDClient({
apiKey: "your-api-key",
fetch: undiciFetch, // Use custom fetch implementation
});const baseClient = new FREDClient({ apiKey: "your-api-key" });
// Create a client with different retry settings
const retryClient = baseClient.with({
retry: { maxRetries: 5 },
});
// Create a cached client for expensive queries
const cachedClient = baseClient.with({
cache: { ttlSeconds: 600, maxEntries: 500 },
});The client is organized into namespaces that mirror the FRED API structure:
client.categories- Browse and search the FRED category structureclient.releases- Access economic data releasesclient.series- Work with data series and observationsclient.sources- Explore data sourcesclient.tags- Search and filter using tagsclient.relatedTags- Discover related tags
For detailed API documentation, see docs/api.md.
All errors are instances of FREDClientError with structured information:
import { FREDClientError } from "@mjesuele/fred-client";
try {
const series = await client.series.get({ seriesId: "INVALID" });
} catch (error) {
if (error instanceof FREDClientError) {
console.error("Status:", error.status); // HTTP status code
console.error("URL:", error.url); // Request URL (API key redacted)
console.error("Params:", error.params); // Request parameters (API key redacted)
console.error("Excerpt:", error.bodyExcerpt); // Response excerpt
// Handle specific errors
if (error.status === 404) {
console.error("Series not found");
} else if (error.status === 429) {
console.error("Rate limited - slow down requests");
}
}
throw error;
}Automatic Retry and Rate Limiting:
const client = new FREDClient({
apiKey: "your-api-key",
retry: {
maxAttempts: 3, // Retry transient errors
baseDelayMs: 1000,
useJitter: true,
},
rateLimit: {
maxBurst: 10,
refillRate: 2, // 2 req/sec = 120/min
},
});
// Requests automatically retry on 429, 500, 502, 503, 504
// Rate limiting prevents hitting API limitsLearn More:
- Error Handling Guide - Complete error documentation
- Retry & Rate Limiting - Configuration options
- Retry Example - Practical examples
This library is written in TypeScript and provides full type definitions:
import type {
FREDClient,
FREDClientConfig,
Series,
Observation,
Page,
PageIterator,
} from "@mjesuele/fred-client";
// All types are exported for your convenience
const config: FREDClientConfig = {
apiKey: "your-api-key",
retry: { maxRetries: 3 },
};
const client = new FREDClient(config);We welcome contributions! Please see CONTRIBUTING.md for:
- Quick start guide (≤15 minutes setup)
- Development workflow
- Coding standards
- Commit message conventions
- Pull request process
Key principles:
- Zero runtime dependencies (NON-NEGOTIABLE)
- TypeScript-first with strict mode
- Native Fetch API only
- 1:1 mapping to FRED API structure
MIT - see LICENSE for details.
This project is not affiliated with or endorsed by the Federal Reserve Bank of St. Louis. FRED® is a registered trademark of the Federal Reserve Bank of St. Louis.