Skip to main content

Basic Usage

After running bunx readonly sync, your files are available for import:
import { documents, config, redirects } from "@readonlystore/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
IntelliSense example

Import Patterns

Named Imports

Import specific files:
import { documents } from "@readonlystore/client";
import { config } from "@readonlystore/client";
import { redirects } from "@readonlystore/client";

Wildcard Import

Import all files at once:
import * as readonly from "@readonlystore/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 "@readonlystore/client";

// elsewhere in your app
import { documents } from "@/lib/readonly";

Common Use Cases

1. Configuration

Store app configuration in ReadOnly:
import { config } from "@readonlystore/client";

const api = axios.create({
	baseURL: config.apiUrl,
	timeout: config.timeout,
});

2. Content Management

Manage blog posts or documentation:
import { posts } from "@readonlystore/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 "@readonlystore/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 "@readonlystore/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 "@readonlystore/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 "@readonlystore/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 "@readonlystore/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 "@readonlystore/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 "@readonlystore/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 "@readonlystore/client";

Build Time Sync

Sync during build to include files in your bundle:
package.json
{
	"scripts": {
		"build": "readonly sync && next build"
	}
}

File Updates

Development

Use watch mode to automatically sync updates:
bunx readonly dev
When you update files in the dashboard, they’ll sync automatically.

Production

Run watch mode alongside your app:
package.json
{
	"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.
Run readonly dev alongside your dev server to automatically sync changes.

Next Steps

CLI Reference

Learn about all available commands.

Configuration

Customize cache and output directories.

Installation

Installation and setup guide.

Troubleshooting

Common issues and solutions.