Basic Usage
After running bunx readonly sync, your files are available for import:
import { documents, config, redirects } from "@readonly/client";
console.log(documents.title);
console.log(config.apiUrl);
console.log(redirects["/old-path"]);
All imports are fully typed with IntelliSense support!
Type Safety
ReadOnly automatically generates TypeScript types by introspecting your JSON files.
Example
Given this JSON file named config:
{
"apiUrl": "https://api.example.com",
"timeout": 5000,
"retries": 3,
"features": {
"darkMode": true,
"analytics": false
},
"endpoints": ["/users", "/posts", "/comments"]
}
ReadOnly generates this type:
export declare const config: {
apiUrl: string;
timeout: number;
retries: number;
features: {
darkMode: boolean;
analytics: boolean;
};
endpoints: string[];
};
IntelliSense
Your editor will provide:
- Auto-completion for all properties
- Type checking
- Inline documentation
- Go-to-definition support
Import Patterns
Named Imports
Import specific files:
import { documents } from "@readonly/client";
import { config } from "@readonly/client";
import { redirects } from "@readonly/client";
Wildcard Import
Import all files at once:
import * as readonly from "@readonly/client";
console.log(readonly.documents);
console.log(readonly.config);
Re-exporting
Re-export for use throughout your app:
// lib/readonly.ts
export { documents, config, redirects } from "@readonly/client";
// elsewhere in your app
import { documents } from "@/lib/readonly";
Common Use Cases
1. Configuration
Store app configuration in ReadOnly:
import { config } from "@readonly/client";
const api = axios.create({
baseURL: config.apiUrl,
timeout: config.timeout,
});
2. Content Management
Manage blog posts or documentation:
import { posts } from "@readonly/client";
export function BlogList() {
return (
<div>
{posts.items.map(post => (
<article key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
</article>
))}
</div>
);
}
3. Redirects
Handle URL redirects:
import { redirects } from "@readonly/client";
export function middleware(request: Request) {
const path = new URL(request.url).pathname;
const redirect = redirects[path];
if (redirect) {
return Response.redirect(redirect, 301);
}
}
4. Feature Flags
Manage feature flags:
import { features } from "@readonly/client";
export function App() {
return (
<div>
{features.darkMode && <DarkModeToggle />}
{features.analytics && <Analytics />}
</div>
);
}
5. Reference Data
Store reference data like countries, currencies, etc:
import { countries } from "@readonly/client";
export function CountrySelect() {
return (
<select>
{countries.map(country => (
<option key={country.code} value={country.code}>
{country.name}
</option>
))}
</select>
);
}
Framework Examples
Next.js
// app/page.tsx
import { documents } from "@readonly/client";
export default function Home() {
return (
<div>
<h1>{documents.title}</h1>
<p>{documents.description}</p>
</div>
);
}
Express
// server.ts
import express from "express";
import { config } from "@readonly/client";
const app = express();
app.listen(config.port, () => {
console.log(`Server running on port ${config.port}`);
});
Remix
// app/routes/_index.tsx
import { json } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import { documents } from "@readonly/client";
export const loader = () => {
return json({ documents });
};
export default function Index() {
const { documents } = useLoaderData<typeof loader>();
return <h1>{documents.title}</h1>;
}
Astro
---
// src/pages/index.astro
import { documents } from "@readonly/client";
---
<html>
<body>
<h1>{documents.title}</h1>
<p>{documents.description}</p>
</body>
</html>
Runtime vs Build Time
Runtime Loading
Files are loaded at runtime from the cache:
// This loads from node_modules/.cache/readonly/documents.json
import { documents } from "@readonly/client";
Build Time Sync
Sync during build to include files in your bundle:
{
"scripts": {
"build": "readonly sync && next build"
}
}
File Updates
Development
Use watch mode to automatically sync updates:
When you update files in the dashboard, they’ll sync automatically.
Production
Run watch mode alongside your app:
{
"scripts": {
"start": "concurrently \"node server.js\" \"readonly dev\""
}
}
Best Practices
Individual files are limited to 10MB. Keep files focused and avoid large datasets.
Name your files descriptively: config, features, redirects, not data1, file2.
Ensure your JSON is valid and follows a consistent structure. ReadOnly validates JSON objects only (no arrays or
primitives at root).
Always run readonly sync before building for production to ensure files are up-to-date.
Use watch mode in development
Run readonly dev alongside your dev server to automatically sync changes.
Next Steps