# Inline Mode vs URL Mode in wren-core-wasm: A Complete Guide for Browser Queries

> Explore inline mode vs URL mode in wren-core-wasm for browser queries. Learn how to pre-register data or stream Parquet files on-demand via HTTP Range requests for efficient queries.

- Repository: [Canner/WrenAI](https://github.com/Canner/WrenAI)
- Tags: deep-dive
- Published: 2026-07-20

---

**Inline mode requires pre-registering data buffers with `registerParquet` before calling `loadMDL`, while URL mode streams Parquet files on-demand via HTTP Range requests by passing a base URL to `loadMDL`.**

The `@wrenai/wren-core-wasm` package from the Canner/WrenAI repository enables WebAssembly-based SQL querying directly in the browser through a semantic layer (MDL). When integrating this engine into client-side applications, developers must choose between two distinct data-loading strategies: **inline mode** for embedded datasets and **URL mode** for remote streaming. Understanding the difference between inline mode and URL mode in wren-core-wasm is critical for optimizing performance and server requirements.

## How Inline Mode Works in wren-core-wasm

**Inline mode** operates by loading data entirely into the browser's memory before query execution. According to the source code in [`core/wren-core-wasm/README.md`](https://github.com/Canner/WrenAI/blob/main/core/wren-core-wasm/README.md) (lines 26-45), the application fetches data files—such as Parquet, CSV, or JSON—and registers them with the engine using explicit API calls.

The workflow requires calling registration methods before initializing the MDL:

```javascript
import { WrenEngine } from '@wrenai/wren-core-wasm';

const engine = await WrenEngine.init();

// Register data buffers before loading MDL
await engine.registerJson('orders', [
  { id: 1, customer: 'Alice', amount: 100 },
  { id: 2, customer: 'Bob', amount: 200 },
]);

// Or register a Parquet buffer fetched manually
const resp = await fetch('orders.parquet');
await engine.registerParquet('orders', await resp.arrayBuffer());

const mdl = {/* … MDL manifest … */};

// Source must be empty string when using inline registration
await engine.loadMDL(mdl, { source: '' });

```

In this mode, the engine stores `ArrayBuffer` instances internally and processes queries against these in-memory buffers. This eliminates network dependencies during query execution but consume memory proportional to the total dataset size.

## How URL Mode Works in wren-core-wasm

**URL mode** leverages DataFusion's `ListingTable` to access remote Parquet files via HTTP without pre-loading the entire dataset. As implemented in [`core/wren-core-wasm/src/lib.rs`](https://github.com/Canner/WrenAI/blob/main/core/wren-core-wasm/src/lib.rs), the engine reads only the specific byte ranges required for each query using HTTP **Range** requests.

The implementation documented in [`core/wren-core-wasm/README.md`](https://github.com/Canner/WrenAI/blob/main/core/wren-core-wasm/README.md) (lines 74-80) shows that URL mode requires only the base URL in the `profile.source` field:

```javascript
import { WrenEngine } from '@wrenai/wren-core-wasm';

const engine = await WrenEngine.init();

const mdl = {/* … MDL manifest … */};

// Provide base URL; no explicit registration needed
await engine.loadMDL(mdl, { source: 'https://cdn.example.com/data/' });

const rows = await engine.query(
  `SELECT customer, SUM(amount) AS total
   FROM "Orders"
   GROUP BY customer`
);

```

DataFusion first requests the file footer to read metadata, then fetches only the specific row groups needed to satisfy the query. This requires the HTTP server to return `206 Partial Content` responses and support **CORS** headers.

## Key Differences Between Inline and URL Mode

### Data Loading Mechanism

**Inline mode** transfers the entire dataset during initialization. The application must fetch files manually and pass `ArrayBuffer` objects to `registerParquet`, `registerCsv`, or `registerJson`. All subsequent queries operate on these retained buffers.

**URL mode** defers data access until query execution. The engine constructs HTTP Range requests dynamically, reading only the Parquet footer first (to determine column statistics), then pulling specific row-group chunks as needed.

### Server Requirements

Inline mode imposes **no server constraints** beyond standard HTTPS hosting. It works with static site hosts, GitHub Pages, or bundled applications that cannot serve custom headers.

URL mode requires servers that support:

- **`Range:`** request headers (essential for partial content delivery)
- **CORS** headers for cross-origin access
- **206 Partial Content** HTTP responses

Servers lacking Range support will cause fetches to hang indefinitely, as documented in [`core/wren-core-wasm/README.md`](https://github.com/Canner/WrenAI/blob/main/core/wren-core-wasm/README.md) (lines 106-110).

### Performance Characteristics

**Inline mode** offers faster query response times after the initial load, since data resides in memory. However, it requires sufficient RAM to hold the entire working set and incurs upfront download costs. The documentation recommends this approach for datasets under approximately **50 MB**.

**URL mode** scales to larger datasets by streaming only necessary data, but each query incurs network round-trip latency. This approach is optimal when serving multi-gigabyte Parquet files from CDNs or when minimizing initial page load times.

## When to Use Inline Mode vs URL Mode

Choose **inline mode** for:

- Local development and demos
- Bundled dashboards where data ships with the application
- Environments without Range header support
- Total dataset sizes below 50 MB

Choose **URL mode** for:

- Large datasets hosted on CDNs (CloudFront, Cloudflare, etc.)
- Scenarios requiring on-demand streaming without upfront downloads
- Production deployments where minimizing bundle size is critical
- Parquet files optimized with sorted columns and predicate pushdown

## Implementation Examples

### Inline Mode Implementation

This example demonstrates the complete inline workflow, including mandatory registration before MDL loading:

```javascript
import { WrenEngine } from '@wrenai/wren-core-wasm';

const engine = await WrenEngine.init();

// Register JSON data
await engine.registerJson('orders', [
  { id: 1, customer: 'Alice', amount: 100 },
  { id: 2, customer: 'Bob',   amount: 200 },
]);

// Or register a Parquet file that you fetched yourself
const resp = await fetch('orders.parquet');
await engine.registerParquet('orders', await resp.arrayBuffer());

const mdl = {/* … MDL manifest … */};

// In inline mode the source is an empty string because tables are pre‑registered
await engine.loadMDL(mdl, { source: '' });

const rows = await engine.query('SELECT * FROM "Orders" LIMIT 5');
console.table(rows);

```

### URL Mode Implementation

This example shows the streamlined URL mode setup, where `profile.source` points to the data directory:

```javascript
import { WrenEngine } from '@wrenai/wren-core-wasm';

const engine = await WrenEngine.init();

const mdl = {/* … MDL manifest … */};

// Provide the base URL where the Parquet files live.
// No explicit register calls are needed.
await engine.loadMDL(mdl, { source: 'https://cdn.example.com/data/' });

const rows = await engine.query(
  `SELECT customer, SUM(amount) AS total
   FROM "Orders"
   GROUP BY customer`
);
console.table(rows);

```

## Summary

- **Inline mode** requires calling `registerParquet`, `registerCsv`, or `registerJson` before `loadMDL`, stores data as `ArrayBuffer` objects in memory, and works best for datasets under 50 MB without special server requirements.
- **URL mode** passes a base URL to `loadMDL` via the `source` parameter, utilizes DataFusion's `ListingTable` with HTTP Range requests, and requires servers supporting CORS and `206 Partial Content` responses.
- The choice depends on data size, server capabilities, and whether you prioritize initial load speed (inline) or scalability (URL).

## Frequently Asked Questions

### Can I use both inline mode and URL mode simultaneously in the same engine instance?

No, the modes are mutually exclusive for a given table. When using inline mode, you must register all tables explicitly with empty `source` strings before calling `loadMDL`. In URL mode, the `source` parameter contains the base URL and the engine ignores any previous `register*` calls, instead attempting to resolve table names as relative paths against the provided URL.

### What happens if my HTTP server does not support Range headers when using URL mode?

Queries will hang or fail because DataFusion cannot read the Parquet file footer or row groups. According to the [`core/wren-core-wasm/README.md`](https://github.com/Canner/WrenAI/blob/main/core/wren-core-wasm/README.md) documentation (lines 106-110), URL mode requires servers that return `206 Partial Content` responses. Without this support, the WebAssembly engine cannot perform the random-access reads necessary for columnar data processing.

### Is there a practical file size limit for inline mode?

While the WebAssembly engine itself imposes no hard limit, the documentation recommends keeping inline datasets under approximately **50 MB**. Beyond this threshold, initial fetch times and memory consumption become prohibitive for browser environments. For larger datasets, migrate to URL mode to leverage HTTP Range request streaming.

### Does URL mode support CSV and JSON files?

No, URL mode specifically requires **Parquet** files because DataFusion's `ListingTable` implementation relies on Parquet's columnar metadata and footer structure to perform efficient Range-based reads. CSV and JSON lack the necessary metadata headers that enable partial file access, so these formats are only available through inline mode using `registerCsv` or `registerJson`.