Node.js
synchronous http.get
JavaScript
asynchronous programming
server-side development

Node.js Is there a synchronous version of the http.get method in node.js?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Node.js does not provide a built-in synchronous http.get. Its I/O model is fundamentally asynchronous and non-blocking. To make HTTP requests that "feel" synchronous, use async/await with the native fetch API (Node 18+), the node-fetch package, or the axios library. For scripts that truly need synchronous HTTP (blocking the event loop), the sync-rpc or execSync workaround exists but is strongly discouraged for production use because it blocks the entire event loop.

Why There Is No Synchronous http.get

Node.js is built on a single-threaded event loop. A synchronous HTTP request would block the entire process — no other requests, timers, or callbacks could execute until the response arrives. This defeats Node.js's core design advantage.

javascript
1// Node's http.get is asynchronous by design
2const http = require('http');
3
4http.get('http://example.com', (res) => {
5    let data = '';
6    res.on('data', (chunk) => { data += chunk; });
7    res.on('end', () => { console.log(data); });
8});
9
10console.log('This runs BEFORE the HTTP response arrives');

Solution 1: async/await with fetch (Node 18+)

Node 18+ includes the global fetch API:

javascript
1async function getData() {
2    const response = await fetch('https://api.example.com/data');
3    const data = await response.json();
4    return data;
5}
6
7// Usage in an async context
8async function main() {
9    const result = await getData();
10    console.log(result);
11    // Code here runs AFTER the HTTP response
12}
13
14main();

await pauses the async function until the promise resolves, making the code read like synchronous code while remaining non-blocking.

Solution 2: async/await with node-fetch (Node < 18)

bash
npm install node-fetch
javascript
1const fetch = require('node-fetch');
2
3async function getData(url) {
4    const response = await fetch(url);
5
6    if (!response.ok) {
7        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
8    }
9
10    return await response.json();
11}
12
13async function main() {
14    try {
15        const data = await getData('https://api.example.com/users');
16        console.log('Users:', data);
17    } catch (error) {
18        console.error('Failed:', error.message);
19    }
20}
21
22main();

Solution 3: async/await with axios

bash
npm install axios
javascript
1const axios = require('axios');
2
3async function getUser(id) {
4    const { data } = await axios.get(`https://api.example.com/users/${id}`);
5    return data;
6}
7
8async function main() {
9    const user = await getUser(42);
10    console.log(user.name);
11
12    // Sequential requests (one after another)
13    const profile = await axios.get(`/api/profile/${user.id}`);
14    const orders = await axios.get(`/api/orders/${user.id}`);
15
16    // Parallel requests (faster)
17    const [profileRes, ordersRes] = await Promise.all([
18        axios.get(`/api/profile/${user.id}`),
19        axios.get(`/api/orders/${user.id}`)
20    ]);
21}
22
23main();

Solution 4: Promisifying http.get

Wrap Node's built-in http.get in a promise:

javascript
1const http = require('http');
2const https = require('https');
3
4function httpGet(url) {
5    return new Promise((resolve, reject) => {
6        const client = url.startsWith('https') ? https : http;
7
8        client.get(url, (res) => {
9            if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
10                // Follow redirect
11                return httpGet(res.headers.location).then(resolve).catch(reject);
12            }
13
14            let data = '';
15            res.on('data', (chunk) => { data += chunk; });
16            res.on('end', () => resolve(data));
17            res.on('error', reject);
18        }).on('error', reject);
19    });
20}
21
22// Usage with async/await
23async function main() {
24    const html = await httpGet('https://example.com');
25    console.log(html.length, 'bytes');
26}
27
28main();

Solution 5: Top-Level await (ES Modules)

In Node 14.8+ with ES modules, you can use await at the top level:

javascript
1// file: script.mjs (or set "type": "module" in package.json)
2
3const response = await fetch('https://api.example.com/data');
4const data = await response.json();
5console.log(data);
6
7// No need for an async main() wrapper

If you absolutely need blocking HTTP (e.g., in a CLI script where event loop is not needed):

javascript
1const { execSync } = require('child_process');
2
3// Use curl in a child process (blocks until complete)
4const result = execSync('curl -s https://api.example.com/data', {
5    encoding: 'utf-8'
6});
7
8const data = JSON.parse(result);
9console.log(data);

Or use the sync-request package:

javascript
1const request = require('sync-request');
2
3const res = request('GET', 'https://api.example.com/data');
4const data = JSON.parse(res.getBody('utf-8'));
5console.log(data);

Both approaches block the entire Node.js process and should only be used in one-off scripts, never in servers.

Comparison

ApproachBlockingDependenciesNode Version
fetch + async/awaitNoNone18+
node-fetch + async/awaitNonode-fetchAny
axios + async/awaitNoaxiosAny
Promisified http.getNoNoneAny
execSync('curl ...')Yescurl installedAny
sync-requestYessync-requestAny

Common Pitfalls

  • Blocking the event loop with synchronous HTTP: Using sync-request or execSync in a web server blocks ALL incoming requests while waiting for the HTTP response. A single slow external API call can make your server unresponsive. Always use async/await in servers.
  • Forgetting to await: const data = fetch(url) returns a Promise, not the data. Without await, you get Promise { <pending> } instead of the response. Always use await fetch(url) inside an async function.
  • Unhandled promise rejections: If fetch fails (network error, timeout) and you do not catch the error, Node.js logs an UnhandledPromiseRejection warning. Always wrap await calls in try/catch blocks.
  • fetch not available in older Node versions: The global fetch was added in Node 18 (experimental in 17). On older versions, use node-fetch or axios. Check your Node version with node --version.
  • Not handling HTTP error status codes: fetch does not throw on 4xx/5xx responses — response.ok is false but no exception is thrown. Always check response.ok or response.status before parsing the body.

Summary

  • Node.js has no synchronous http.get — use async/await for synchronous-looking code
  • Use fetch (Node 18+) or axios for the cleanest async HTTP
  • Wrap callbacks in Promises to use await with older APIs
  • Never use synchronous HTTP in production servers — it blocks the event loop
  • Use try/catch with await to handle network errors and non-2xx responses

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.