How to Read a JSON File in JavaScript
There are three main approaches to read a JSON file in JavaScript: require() for quick synchronous loading in Node.js, fs.promises.readFile for async production code, and fetch() for the browser. Each has different tradeoffs around caching, blocking, and environment support.
Have a JSON file you want to inspect or validate? Paste it into Jsonic's formatter to check it instantly.
Test your JSON in the browserMethod 1: require() — the fastest way in Node.js
require() is the simplest way to load a JSON file in Node.js. It reads, parses, and caches the file synchronously — no JSON.parse needed.
const data = require('./data.json')
console.log(data.name) // access properties directlyCaching caveat: Node.js stores the parsed result in the module cache. If the file changes on disk after the first require(), subsequent calls return the original cached object — not the updated file. For config files read once at startup this is fine; for files that change at runtime, use fs.promises.readFile instead.
require() also blocks the event loop while reading. For small config files at application startup this is acceptable, but avoid it inside request handlers or hot code paths.
Method 2: fs.readFileSync — synchronous, no caching
fs.readFileSync reads the raw file contents as a string. You must parse the string yourself with JSON.parse. Unlike require(), it always reads from disk, so it reflects the current file contents.
const fs = require('fs')
const raw = fs.readFileSync('./data.json', 'utf8')
const data = JSON.parse(raw)
console.log(data)Use this for scripts, build tools, and CLI commands where blocking is acceptable and you need fresh data on every read. Avoid it inside Express route handlers or any async context where blocking the event loop causes latency.
Method 3: fs.promises.readFile — async, production-ready
For server applications, prefer the async version so the event loop stays free while the OS reads the file. fs.promises.readFile (also importable as fs/promises) returns a promise you can await.
const fs = require('fs/promises')
async function loadJson(filePath) {
const raw = await fs.readFile(filePath, 'utf8')
return JSON.parse(raw)
}
const data = await loadJson('./data.json')
console.log(data)This is the recommended pattern for Node.js 12+ production code. The 'utf8' encoding argument makes readFile return a string instead of a Buffer, which is what JSON.parse expects.
Method 4: Dynamic import() for ESM projects
Node.js 17.5+ supports JSON modules via the import() expression with an import assertion (or "import attribute" in newer syntax). This is the idiomatic way to load JSON in an ES module project ("type": "module" in package.json).
// Node.js 17.5–21: import assertions (deprecated but still supported)
const { default: data } = await import('./data.json', {
assert: { type: 'json' }
})
// Node.js 22+: import attributes (current syntax)
const { default: data } = await import('./data.json', {
with: { type: 'json' }
})
console.log(data)Note: the imported value is wrapped in a module object. The actual data is on .default. Also note that dynamic import() caches results the same way require() does.
If you are using a static import statement (top of file), enable resolveJsonModule: true in tsconfig.json for TypeScript projects and use:
import data from './data.json' with { type: 'json' }Method 5: fetch() in the browser
Browsers have no access to the local filesystem. To load a JSON file client-side, serve it over HTTP and use the Fetch API. The response.json() method parses the body automatically.
async function loadJson(url) {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`HTTP error ${response.status}`)
}
return response.json()
}
const data = await loadJson('/api/data.json')
console.log(data.title)Always check response.ok before calling response.json(). A 404 or 500 response does not throw by itself — the promise only rejects on network failures (DNS error, no connection). An HTTP error status is considered a successful network request.
For more fetch patterns including POST, headers, and error handling, see the Fetch JSON in JavaScript guide.
Error handling: ENOENT, SyntaxError, and type errors
Two classes of errors are common when reading JSON files: the file does not exist (ENOENT) and the file contents are not valid JSON (SyntaxErrorfrom JSON.parse). Handle them separately so callers get actionable messages.
const fs = require('fs/promises')
async function readJson(filePath) {
try {
const raw = await fs.readFile(filePath, 'utf8')
return JSON.parse(raw)
} catch (err) {
if (err.code === 'ENOENT') {
throw new Error(`File not found: ${filePath}`)
}
if (err instanceof SyntaxError) {
throw new Error(`Invalid JSON in ${filePath}: ${err.message}`)
}
throw err // re-throw unexpected errors
}
}
// Usage
try {
const config = await readJson('./config.json')
console.log(config)
} catch (err) {
console.error(err.message)
process.exit(1)
}Other useful error codes: EACCES means the process lacks permission to read the file; EISDIR means the path points to a directory, not a file. Always re-throw errors you don't explicitly handle — swallowing unknown errors makes debugging much harder.
TypeScript: typed JSON reading
Define an interface for the expected JSON shape and cast the parsed result. This gives you compile-time type checking on every property access without any runtime overhead.
import { readFile } from 'fs/promises'
interface Config {
host: string
port: number
debug: boolean
allowedOrigins: string[]
}
async function readConfig(filePath: string): Promise<Config> {
const raw = await readFile(filePath, 'utf8')
return JSON.parse(raw) as Config
}
// Usage
const config = await readConfig('./config.json')
console.log(config.host) // string — fully typedNote: the as Config cast is a compile-time assertion — TypeScript trusts you. If the JSON file has unexpected shape at runtime, you won't get a type error, you'll get undefined on property access. For strict validation, use a library like zod or ajv to validate the parsed value against your schema at runtime.
Alternatively, enable resolveJsonModule: true in tsconfig.json to import JSON files with full inferred types:
// tsconfig.json
{
"compilerOptions": {
"resolveJsonModule": true,
"esModuleInterop": true
}
}
// your-file.ts
import config from './config.json'
// config is fully typed based on the JSON file structureComparison: which method to use?
| Method | Environment | Sync / Async | Use When |
|---|---|---|---|
require('./file.json') | Node.js (CJS) | Sync (cached) | Small config, module-level load at startup |
fs.readFileSync | Node.js | Sync | Scripts, CLI tools, build-time reading |
fs.promises.readFile | Node.js | Async | Production servers, avoid blocking event loop |
import() with type assertion | Node.js 17.5+ (ESM) | Async (cached) | ES module projects using dynamic imports |
fetch('/file.json') | Browser | Async | Client-side data loading from a server |
Frequently asked questions
How do I read a JSON file in Node.js?
The fastest way is const data = require('./data.json'). For async code that doesn't block the event loop, use const raw = await fs.readFile(path, 'utf8'); return JSON.parse(raw) with the fs/promises module.
What is the difference between require and fs.readFileSync for JSON?
require() automatically parses JSON and caches the result — later calls return the same object without hitting the disk again. fs.readFileSyncreads the raw file as a string (you parse it yourself) and always reads from disk, so it reflects changes made after the application started.
How do I read a JSON file asynchronously in JavaScript?
In Node.js, use fs.promises.readFile(path, 'utf8') and await the result, then call JSON.parse on the string. In the browser, use fetch(url).then(r => r.json()). Both approaches are non-blocking.
How do I read a JSON file in the browser without Node.js?
Use the Fetch API: const data = await fetch('/data.json').then(r => r.json()). The file must be served over HTTP — browsers cannot read local files from the filesystem for security reasons.
How do I handle errors when reading a JSON file in JavaScript?
Wrap the read and parse in try/catch. Check err.code === 'ENOENT' for missing files and err instanceof SyntaxError for invalid JSON content. Always re-throw errors you don't specifically handle so they're not silently swallowed.
Can I read a JSON file with TypeScript?
Yes. Use fs.promises.readFile and cast: JSON.parse(raw) as YourType. For compile-time inference of the JSON shape, enable resolveJsonModule: truein tsconfig.json and use a static import statement.
Validate your JSON in the browser
Before reading a JSON file in code, check it for syntax errors in Jsonic's online formatter. Paste the file contents and see errors highlighted instantly.
Open JSON Formatter