Try an advanced form of SQL right on your database.
LinkedQL is a database client (client.query()) that solves the modern database capability problem in a single interface β and in under 80 KiB min | zip.
Relationships β’ JSON β’ Schema β’ Reactivity β’ Versioning β’ Offline β SOLVED
| Entry Point | Capabilities | More |
|---|---|---|
| Quick Start | Language Capabilities | What is LinkedQL |
| Clients & Dialects | Runtime Capabilities | Documentation |
| Query Interface | Offline Capabilities | Progress |
LinkedQL is distributed as an npm package. Install it with:
npm install @linked-db/linked-qlThe package provides clients for all supported SQL dialects β including FlashQL, the in-memory SQL engine for local or offline use.
Import and initialize the client for your use case. You can run either fully in-memory or with a database. Here are two quick examples:
FlashQL lets you run SQL queries entirely in memory β with zero setup.
import { FlashClient } from '@linked-db/linked-ql/flash';
const client = new FlashClient();
const result = await client.query(`
CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT);
INSERT INTO users (name) VALUES ('Ada'), ('Linus');
SELECT * FROM users;
`);
console.log(result.rows);
// [{ id: 1, name: 'Ada' }, { id: 2, name: 'Linus' }]FlashQL is ideal for:
- Local-first and offline-first apps
- Running SQL over runtime data
- Testing and prototyping
Connect to your database from the list of supported dialects below. Hereβs an example using PostgreSQL:
import { PGClient } from '@linked-db/linked-ql/pg';
const client = new PGClient({
host: 'localhost',
port: 5432,
user: 'postgres',
password: 'password',
database: 'myapp',
});
await client.connect();
const result = await client.query(`SELECT 10 AS value`);
console.log(result.rows); // [{ value: 10 }]
await client.disconnect();| Dialect | Import Path | Guide |
|---|---|---|
| PostgreSQL | @linked-db/linked-ql/pg |
PostgreSQL β |
| MySQL | @linked-db/linked-ql/mysql |
MySQL β |
| MariaDB | @linked-db/linked-ql/mariadb |
MariaDB β |
| FlashQL (In-Memory) | @linked-db/linked-ql/flash |
FlashQL β |
LinkedQL maintains a unified and familiar interface across all dialects β whether remote or local. Method signatures and return values are consistent and documented in the Client API Reference β
Note
Youβre viewing @linked-db/linked-ql β the newest iteration.
For the prev 0.3.x branch, see linked-db/linked-ql@0.3.*.
Important
π LinkedQL is in active development and evolving daily. Current status = alpha.
Youβre welcome to experiment, but itβs not yet suited for production workloads.
| Feature | Summary | Docs |
|---|---|---|
| DeepRefs | Follow foreign key relationships directly in simple arrow notation. | Read β DeepRefs Docs |
| JSON Literals | Model JSON objects and arrays using literal JSON syntax. | Read β JSON Docs |
| UPSERT | Perform the classic INSERT...ON CONFLICT statement in a single step. |
Read β UPSERT Docs |
(a) JSON Literals β Structured Projection
Model JSON objects and arrays using literal JSON syntax.
const result = await client.query(`
SELECT
id,
{ first: first_name, last: last_name } AS name,
{ email, phone: phone_number } AS contact
FROM users
`);
console.log(result.rows[0]);
// { id: 1, name: { first: 'Jane', last: 'Dark' }, contact: { email: 'jane@example.com', phone: null } }(b) DeepRefs β Relationship Traversal
Follow foreign key relationships directly in simple arrow notation.
const posts = await client.query(`
SELECT title, author ~> { name, email }
FROM posts
WHERE published = true;
`);
console.log(posts.rows[0]);
// { title: 'Syntax Shorthands', author: { name: 'John', email: 'john@example.com' } }(c) UPSERT β Insert or Update
Perform the classic
INSERT...ON CONFLICTstatement in a single step.
await client.query(`
UPSERT INTO users (id, name, email)
VALUES
(1, 'Jane', 'jane@example.com'),
(2, 'James', 'j2@example.com');
`);| Feature | Summary | Docs |
|---|---|---|
| Live Queries | Turn on reactivity over any query and get back a live view of your data. | Read β RealtimeSQL Docs |
| Timeline Engine | Anchor a query to a fixed schema version for stable results over time. | (Coming soon) |
(a) Live Queries and Live Views
Turn on reactivity over any query and get back a live view of your data.
const result = await client.query(`
SELECT p.title, u.name
FROM posts AS p LEFT JOIN users AS u ON p.author = u.id
WHERE p.published = true
ORDER BY p.created_at DESC
`, { live: true });
setInterval(() => console.log(result.rows), 1000);
// Updates automatically as post or author data changes(b) Live Queries + DeepRefs
Combine live results with relational traversal and JSON shaping.
const result = await client.query(`
SELECT
{ title, category } AS post,
author ~> { name, email } AS author
FROM posts WHERE published = true
`, { live: true });(c) Version Binding β Point-in-Time Queries
Anchor a query to a fixed schema version for stable results over time.
const result = await client.query(`
SELECT name, email
FROM users@2_3
WHERE active = true;
`);LinkedQL bundles an embeddable SQL engine, FlashQL, that brings its full capabilities to the local runtime, the edge, and offline world.
| Capability | Summary | Docs |
|---|---|---|
| Local Database | Run a full SQL engine in memory β same semantics, zero setup. | Read β FlashQL Docs |
| Federation | Query local and remote data together in a single SQL surface. | Read β FlashQL Docs |
| Sync | Keep local and remote tables automatically synchronized. | Read β FlashQL Docs |
(a) Local Database β Runs Anywhere
Run a full SQL engine in memory β same semantics, zero setup.
import { FlashClient } from '@linked-db/linked-ql/flash';
const client = new FlashClient();
await client.query(`CREATE TABLE users (id SERIAL, name TEXT)`);
await client.query(`INSERT INTO users (name) VALUES ('Alice'), ('Bob')`);
const result = await client.query(`SELECT JSON_AGG(name) AS users FROM users`);
console.log(result.rows);
// [{ users: ['Alice', 'Bob'] }](b) Federation β Local + Remote
Query local and remote data together in a single SQL surface.
await client.federate({ store: ['orders'] }, remoteConfig);
const result = await client.query(`
SELECT u.name, COUNT(o.id) AS total_orders
FROM users AS u LEFT JOIN store.orders AS o ON o.user_id = u.id
GROUP BY u.id ORDER BY total_orders DESC;
`);(c) Sync β Continuous Alignment
Keep local and remote tables automatically synchronized.
await client.sync({ store: ['orders'] }, remoteConfig);
client.on('sync:status', s => console.log('Sync status:', s.state));
client.on('sync:change', e => console.log('Ξ', e.table, e.type));| Feature | Description | Wiki Page |
|---|---|---|
| DeepRefs | Declarative relationship traversal across foreign keys. | DeepRefs β |
| JSON Literals | Inline JSON modeling syntax β objects, arrays, aggregations. | JSON Literals β |
| UPSERTS | Simplified INSERT + UPDATE hybrid statement. |
UPSERTS β |
| RealtimeSQL | Live queries powered by the Realtime Engine. | RealtimeSQL β |
| FlashQL | In-memory SQL runtime for offline, edge, and hybrid apps. | FlashQL β |
| Component | Status | Note |
|---|---|---|
| Parser & Compiler | π© 100% |
Stable |
| Transform Engine | π© 100% |
Stable |
| Drivers (PG/MySQL) | π© 97% |
Complete; MySQL nearing parity |
| FlashQL Engine | π© 99% |
Expanding |
| Realtime Engine | π© 99% |
Expanding |
| Timeline Engine | π¨ 20% |
Planned |
| Migration Wizard | β¬ 10% |
Planned |
| IDE Tooling | β¬ 5% |
Early hooks |
| Docs (vNext) | π© 95% |
Expanding |
Status Legend:
π© Complete | π¨ In Progress | β¬ Not Started
LinkedQL is in active development β and contributions are welcome!
Hereβs how you can jump in:
- Issues β Spot a bug or have a feature idea? Open an issue.
- Pull requests β PRs are welcome for fixes, docs, or new ideas.
- Discussions β Not sure where your idea fits? Start a discussion.
β€· clone β install β test
git clone https://github.com/linked-db/linked-ql.git
cd linked-ql
git checkout next
npm install
npm test- Development happens on the
nextbranch β be sure to switch to it as above after cloning. - Consider creating your feature branch from
nextbefore making changes (e.g.git checkout -b feature/my-idea). - Remember to
npm testbefore submitting a PR. - Check the Progress section above to see where help is most needed.
MIT β see LICENSE